## Functors in Scala

Following on my earlier entry on modules in Scala, I'll give an encoding of Standard ML style functors here. You can get a pretty close approximation by using `class`

constructor arguments. However, I am going to cheat a little to get the closest encoding I think is possible by using the experimental support for dependent method types. You can get this by running `scala`

or `scalac`

with the option `-Xexperimental`

. It works okay at least some of the time, but no one has the time at the moment to commit to getting it in shape for general consumption.

So here is my example of how the encoding works. First, the SML version:

signature Eq = sig type t val eq: t -> t -> bool end signature RicherEq = sig include Eq val neq: t -> t -> bool end functor mkRicherEq(arg : Eq) :> RicherEq where type t = arg.t = struct type t = arg.t val eq = arg.eq fun neq x y = not (eq x y) end

We can transliterate this example into Scala as:

type Eq = { type T def eq(x: T, y: T): Boolean } type RicherEq = { type T def eq(x: T, y: T): Boolean def neq(x: T, y: T): Boolean } def mkRicherEq(arg: Eq) : RicherEq { type T = arg.T } = new { type T = arg.T def eq(x: T, y: T) = arg.eq(x, y) def neq(x: T, y:T) = !eq(x, y) }

The only problem I discovered is that it is not possible to define `RicherEq`

in terms of `Eq`

as we could in SML:

scala> type RicherEq = Eq { def neq(x: T, y: T): Boolean } <console>:5: error: Parameter type in structural refinement may not refer to abstract type defined outside that same refinement type RicherEq = Eq { def neq(x: T, y: T): Boolean } ^ <console>:5: error: Parameter type in structural refinement may not refer to abstract type defined outside that same refinement type RicherEq = Eq { def neq(x: T, y: T): Boolean } ^

Why this restriction exists I don't know. In fact, this sort of refinement should work in the current version of Featherweight Scala, so perhaps it can be lifted eventually.

I still need to think about higher-order functors, and probably spend a few minutes researching existing proposals. I think this is probably something that cannot be easily supported in Scala if it will require allowing method invocations to appear in paths. However, off hand that only seems like it should be necessary for applicative higher-order functors, but again I definitely need to think it through.

## Ross said,

April 11, 2014 @ 9:04 am

Scala is quite sensitive to versions. I’m not sure what Scala version the above code works in. However, for 2.10.3, the following code works, but the above code doesn’t work.

abstract class Eq {

type T

def eq(x: T, y: T): Boolean

}

abstract class RicherEq {

type T

def eq(x: T, y: T): Boolean

def neq(x: T, y: T): Boolean

}

def mkRicherEq(arg : Eq) : RicherEq { type T = arg.T } = new RicherEq {

type T = arg.T

def eq(x: arg.T, y: arg.T) = arg.eq(x, y)

def neq(x: T, y:T) = !eq(x, y)

}

Note: For 2.9.x neither works and Xexperimental makes no difference.

## washburn said,

May 8, 2014 @ 2:02 pm

Ross, the only issue with your version is that it doesn’t capture the structural subtyping of the SML version. However, it is debatable how important that is in practice.