mh - haskell
http://matt.immute.net/taxonomy/term/13/0
en"Pentecostal movements"
http://matt.immute.net/content/pentecostal-movements
<p>This is a <a href="http://lambda-the-ultimate.org/node/92#comment-45708">funny and very insightful comment</a> about programming practice from Kay Schluehr:</p>
<blockquote><p>
I think people grasp rather well that IO has to be specially treated in Haskell after giving them a short explanation. They are more puzzled about "monad oriented programming" as the latest programming paradigm and hardly anyone has sold it as such yet. A programming paradigm is not about immediate utility (e.g. the IO monad as a special solution for a particular problem that can be ignored in non-lazy languages ) but about design value. It's the promise of having a benefit from organizing code in a certain way and it is also always a belief system because good design cannot be benchmarked. A paradigm is a mindset that can reverse the relationship between utility and value: the IO monad is not a special hack anymore but it is the right thing to do from the very beginning while everyone else does it essentially wrong or simply "doesn't get it".</p>
<p>Once the pentecostal movement of a new paradigm has been activated it is unremarkable that so many people are talking about their experiences with monads, that so many tutorials are written about them or even that you try to explain/excuse your own initial confusion and highlights the moments of clarity. We might not believe in the father and the son anymore but at least in the holy spirit.
</p></blockquote>
<p>I find that I have nothing to add.</p>
http://matt.immute.net/content/pentecostal-movements#commentshaskellprogrammingMon, 05 Jan 2009 15:51:53 -0600matt43 at http://matt.immute.netGeneralizing Functor
http://matt.immute.net/content/generalizing-functor
<p>(From a couple of conversations in #haskell...) The other day, Peaker was trying to characterize a relationship between <code>Arrow</code> and <code>Functor</code>. I'm not sure I understood his intuition, but there's one relationship that seemed obvious to me...<br />
<!--break--></p>
<p>The <code>Category</code> class represents categories whose objects are Haskell types. <em>Hask</em> is one such category, but obviously there are many others.</p>
<pre>
class Category c where
id :: c a a
(.) :: c b d -> c a b -> c a d
</pre><p>An instance of <code>Category</code> represents a category in terms of its hom-objects in <em>Hask</em>. In other words, the type <code>c a b</code> (as an object in <em>Hask</em>) represents the set of morphisms <em>a -> b</em> in the category <em>C</em> defined by the instance.</p>
<p>(Aside: Values of type <code>c a b</code> represent individual <em>C</em>-morphisms <em>a -> b</em>, as the definition of <code>id</code> makes clear, but when working with categories, we're forced into a point-free style, because we have no notion of lambda abstraction for an arbitrary category.)</p>
<p>Anyway, all this is to say that we're representing a category <em>C</em> by its hom-functor <code>c</code>: <em>C x C -> Hask</em> (or really <em>C -> C -> Hask</em>, but let's ignore that detail...), so we'd expect the type constructor <code>c</code> to be a bi-functor. In particular, we'd expect the type constructor <code>c a</code> to be a functor. But we run into trouble if we try to say so:</p>
<pre>
instance Category c => Functor (c a) where
f `fmap` x = ?
</pre><p>We find that we need a way of lifting an arbitrary function <code>a -> b</code> to <code>c a b</code>, which certainly doesn't make sense, and would be a significant restriction on the categories we can represent. (Is this related to people's distaste for <code>arr</code> in Arrows? I think so...) The problem is that <code>Functor</code> only represents functors <em>Hask -> Hask</em>, but <code>c a</code> is a functor <em>C -> Hask</em>. It doesn't matter for the object mapping of the functor, but for <code>fmap</code>, which provides the arrow mapping, it does.</p>
<p>So this leads me to want a "generalized" functor, although really it's just a regular functor that's not restricted to be an endofunctor on <em>Hask</em>. We can write it with type families:</p>
<pre>
class Gunctor f where
type Cat1 f :: * -> * -> *
type Cat2 f :: * -> * -> *
gmap :: Cat1 f a b -> Cat2 f (f a) (f b)
</pre><p>
And now we can express the relationship between <code>Category</code> and <code>Gunctor</code> quite elegantly:</p>
<pre>
instance Category cat => Gunctor (cat a) where
type Cat1 (cat a) = cat
type Cat2 (cat a) = (->)
gmap = (.)
</pre><p>This simply states quite literally what we already knew: that <code>Category</code> represents a category in terms of its hom-objects in <em>Hask</em>.</p>
<p>Of course, all instances of <code>Functor</code> are also "generalized" functors:</p>
<pre>
newtype WrappedFunctor f a = WrapFunctor { unwrapFunctor :: f a }
instance Functor f => Gunctor (WrappedFunctor f) where
type Cat1 (WrappedFunctor f) = (->)
type Cat2 (WrappedFunctor f) = (->)
gmap f = WrapFunctor . fmap f . unwrapFunctor
</pre><p>
Meanwhile, Cale was musing about another generalization of <code>Functor</code>, and defining <code>(.)</code> for arbitrary functors. I can only understand what he means if we first move from <code>Functor</code> to <code>Gunctor</code>, but I wonder if he actually meant something else...</p>
<p>Anyway, is this useful? I don't know, possibly not. This level of abstraction starts to give GHC a <em>lot</em> of trouble, even with 6.10.1, and it gives my brain some trouble as well. But I tend to feel that way about arrows as a whole, so if arrows are useful, perhaps this more general functor is too.</p>
http://matt.immute.net/content/generalizing-functor#commentshaskellFri, 19 Dec 2008 17:53:05 -0600matt42 at http://matt.immute.netPointless fun
http://matt.immute.net/content/pointless-fun
<p>At the end of my <a href="/content/clearer-point-free-style">last post</a>, I posed a question: can we write combinators that allow us to write something like this:</p>
<pre>argument length . (result.argument) length $ compare</pre><p>more like this:</p>
<pre>compare <$> length <*> length</pre><p>(Of course, we aren't really looking for an instance of <code>Applicative</code>, so the actual combinators will be different. But you see the idea...)</p>
<p>After a bit of thought, I've found that we can solve this pretty easily. I suspected that the solution would involve type classes, but it doesn't. If we compromise (or generalize) and add a transformer for the result type as well, we can define <code>($.)</code> and <code>(~>)</code> so that we can write:</p>
<pre>compare $. length ~> length ~> id</pre><p>Implementation follows...<!--break--></p>
<p>Recall that the above is a point-free version of</p>
<pre>\x y -> compare (length x) (length y)</pre><p>In effect, we want to be able to apply a curried function to "argument transformers" rather than directly to arguments. In other words, we want to go from</p>
<pre>foo :: a -> b -> c</pre><p>to</p>
<pre>foo' :: (a' -> a) -> (b' -> b) -> c</pre><p>As I said, we'll make one compromise, which is actually a generalization. We'll allow ourselves to transform the result type as well, leaving us with something like</p>
<pre>foo'' :: (a' -> a) -> (b' -> b) -> (c' -> c)</pre><p>
We'll make use of two of Conal's combinators:</p>
<pre>
result = (.)
argument = flip (.)
</pre><p>but we'll also give them shorter names:</p>
<pre>
r = result
a = argument
</pre><p>
The goal is to build up a chain like this:</p>
<pre>
f g => a g $ f
f g h => a g . (r.a) h $ f
f g h i => a g . (r.a) h . (r.r.a) i $ f
</pre><p>Ignore the <code>f</code>s for now. We rely on two facts: first, that <code>result</code> "distributes" across <code>(.)</code>:</p>
<pre>(r.a) h . (r.r.a) i == r (a h . (r.a) i)</pre><p>and second, that <code>result id</code> does nothing:</p>
<pre>result id f == id . f == f</pre><p>
So our chain is equivalent to:</p>
<pre>
a g . r id $ f
a g . r (a h . r id) $ f
a g . r (a h . r (a i . r id)) $ f
</pre><p>So our answer will use one combinator to build up the chain of transformations, and another to stick on the <code>f</code>, which we'd prefer to appear at the beginning.</p>
<p>Writing down the answer is pretty straightforward:</p>
<pre>
infixr 2 ~>
f ~> g = argument f . result g
infixl 1 $.
($.) = flip ($)
</pre><p>
And now we can write:</p>
<pre>compare $. length ~> length ~> id</pre><p>The transformer to the right of <code>($.)</code> looks like the type of the function to the left, and includes one operation to apply at each argument. <code>id</code> matches whatever is left (in this case, just the result).</p>
<p>A few things to notice:</p>
<ul>
<li>Since these are curried functions, we only need to mention as many arguments as we like. <code>id</code> will take care of the rest. So we can write things like:<br />
<pre>compare $. length ~> id</pre></li>
<li>The transformers can be as complex as we like:<br />
<pre>compare $. length ~> length.head ~> id</pre></li>
<li>We can chain whole sequences, in the obvious way:<br />
<pre>compare $. length ~> length ~> id $. id ~> head ~> id</pre><p>which is of course equal to the above.</li>
</ul>
<p>Is it useful? I'm not sure. There have been plenty of times when I've wanted it, but I've always found another way. Does it already exist? I'd love to know, and I'd also love to hear better names for <code>($.)</code> and <code>(~>)</code>...</p>
http://matt.immute.net/content/pointless-fun#commentshaskellWed, 03 Dec 2008 01:09:59 -0600matt41 at http://matt.immute.netA clearer point-free style
http://matt.immute.net/content/clearer-point-free-style
<p>Conal Elliott has been explaining (<a href="http://conal.net/blog/posts/semantic-editor-combinators/">1</a>, <a href="http://conal.net/blog/posts/prettier-functions-for-wrapping-and-wrapping/">2</a>) what he calls <em>semantic editor combinators</em>, which I've also seen referred to as <em><code>(fmap.fmap)</code> style</em>. It's great stuff. Simple, clear, and a big payoff. For a long time, I've wanted a better (read: clearer) way of transforming arguments of curried functions. Arrow combinators never quite seemed to fit the bill, focusing as they do on pairs, and sections of <code>(.)</code> are just too cryptic for me.</p>
<p>As an example, suppose we didn't have <code>Data.Ord.comparing</code>, but only <code>compare</code>. If we want to compare lists by length, say, we can now write:</p>
<pre>argument length . (result.argument) length $ compare</pre><p>which I actually find reasonably clear. Now it's easy, for example, to transform just the third argument of a curried function. Very cool. (In complicated cases, we'll quickly want a family of combinators like <code>cadddr</code>, <code>cdadr</code>, etc., but there are worse things...)</p>
<p>In common cases like <code>compare</code>, though, where we really want to transform a whole series of arguments, one would really love a class like <code>Applicative</code> to do the trick:</p>
<pre>compare <$> length <*> length ==
\x y -> compare (length x) (length y)</pre><p>Of course that doesn't work, but it would be really nice to be able to write this kind of composition in a similar applicative style.</p>
<p>Is it possible to write a type class to do this? Has someone done it?</p>
http://matt.immute.net/content/clearer-point-free-style#commentshaskellTue, 02 Dec 2008 15:02:00 -0600matt40 at http://matt.immute.netCoincidence?
http://matt.immute.net/content/coincidence
<p>These two books, long ago separately pre-ordered, arrived from different places on the same day:<br />
<a href="http://www.flickr.com/photos/hellige/3075888733/" title="today's mail by hellige, on Flickr"><img src="http://farm4.static.flickr.com/3059/3075888733_5c6264363d.jpg" width="500" height="375" alt="today's mail" /></a><br />
One of the things keeping me busy lately has been a Haskell reading group, which has mostly amounted to me teaching some people Haskell, using this book as the main text. We've been using the web preprint, and it's exciting to see the real thing!</p>
<p>For a long time, I've felt that there were lots of decent "first books" on Haskell, but not a single "second book." This is especially unfortunate, given that the most difficult part for many people of learning Haskell is making the jump from CS101 stuff to the actual state of the art. This book rectifies that. In fact, having used it with beginners, I'm not sure I'd recommend it as the best very first book on Haskell, but that hardly matters. Since a lot of this material has until now had to be painstakingly gleaned from mailing list archives, conference papers, functional pearls, blogs and sometimes IRC, this is a very welcome reference. It's exciting to see a Haskell book that goes beyond the basics.</p>
<p>I haven't gotten all the way through it yet, but I'd already happily recommend it. And of course it's great to see the first Scala book in print as well. I understand that 2009 will witness a number of unfortunately similarly named titles. Too bad about the names, otherwise it's a great trend. Congratulations to all six authors of these two books!</p>
http://matt.immute.net/content/coincidence#commentshaskellscalaMon, 01 Dec 2008 23:23:26 -0600matt39 at http://matt.immute.netFunctional programming to the rescue
http://matt.immute.net/content/functional-programming-rescue
<p>Three days of JavaOne was enough to completely sour me on the entire idea of programming. I'm not really sure what did it. But then I made the <em>right decision</em> and went to the <a href="http://www.bayfp.org/">BayFP</a> meeting. I left feeling quite rejuvenated, my faith in humanity and love of programming fully restored.</p>
<p>I even won a book for being evidently the only person in the room (other than <a href="http://www.serpentine.com/blog/">the speaker</a>) who has been programming in Haskell for more than five years. But someone else seemed more interested, so I gave it away. And in any case, I'm quite sure I'm just the only one who raised my hand.</p>
<p>I encourage everyone to start getting excited about <a href="http://book.realworldhaskell.org/">Real-World Haskell</a>. I really don't think you'll be disappointed.</p>
<p>Finally, I really wish for a Chicago Functional Programmers group. Unfortunately, I'd probably have to organize it myself...</p>
http://matt.immute.net/content/functional-programming-rescue#commentshaskellprogrammingFri, 09 May 2008 01:44:21 -0500matt33 at http://matt.immute.netHitting the wall
http://matt.immute.net/content/hitting-wall
<p>In my <a href="/content/scala-vs-skalleh">last post</a>, I translated the first part of <a href="http://lambda-the-ultimate.org/node/2700">Data types a la carte</a> into Scala. I decided to push ahead into the next section, just for fun. The summary is: Scala's implicits are a <em>very</em> poor man's type classes, at least using the obvious encoding, and I am as always humbled by the cleverness of GHC.<!--break--></p>
<p>Things start out ok:</p>
<pre>
trait Less[Sub[_],Sup[_]] {
val subF: Functor[Sub]
val supF: Functor[Sup]
def inj[A](sub: Sub[A]): Sup[A]
def prj[A](sup: Sup[A]): Option[Sub[A]]
}
implicit def ReflLess[F[_]](fF: Functor[F]) =
new Less[F,F] {
val subF = fF
val supF = fF
def inj[A](sub: F[A]): F[A] = sub
def prj[A](sup: F[A]): Option[F[A]] = Some(sup)
}
</pre><p>The other two instances, LeftLess and RightLess, are equally obvious. Recall that the point here is to treat Sum as a cons-list, so we'll have two more instances like:</p>
<pre>
implicit def LeftLess[F[_],G[_]](fF: Functor[F], gF: Functor[G]) =
new Less[F,Apply2Of3[Sum,F,G]#It] { ... }
implicit def RightLess[F[_],G[_],H[_]](fF: Functor[F], gF: Functor[G],
hF: Functor[H], fgLess: Less[F,G]) =
new Less[F,Apply2Of3[Sum,H,G]#It] { ... }
</pre><p>but I won't bother to show them.</p>
<p>The point of this exercise is to make it easier to write expressions like the last post's addExample. So we define:</p>
<pre>
def inject[F[_],G[_]](g: G[Expr[F]])(implicit gfLess: Less[G,F]): Expr[F] =
Expr[F](gfLess.inj(g))
def value[F[_]](v: Int)(implicit less: Less[Val,F]): Expr[F] =
inject[F,Val](Val(v))
def sum[F[_]](l: Expr[F], r: Expr[F])(implicit less: Less[Add,F]): Expr[F] =
inject[F,Add](Add(l,r))
</pre><p>
Unfortunately, this is pretty much where the fun ends. We'd really like to write something like:</p>
<pre>
val addExample2: Expr[Apply2Of3[Sum,Val,Add]#It] =
value(30000) |+| value(1330) |+| value(7)
</pre><p>But first, we can't define sum as an infix operator without an implicit conversion, so we'll try this first:</p>
<pre>
sum(value(30000), sum(value(1330), value(7)))
</pre><p>It's not great, but it's workable, and we could try an implicit conversion if we really want the infix syntax. But in fact the problems are much worse. First, we need to add a type annotation to <em>every single</em> application:</p>
<pre>
type Tmp[X] = Apply2Of3[Sum,Val,Add]#It[X]
val addExample2 = sum[Tmp](value[Tmp](30000),
sum[Tmp](value[Tmp](1330), value[Tmp](7)))
</pre><p>But then we have problems with implicits: Scala is incapable of chaining the implicit conversions necessary to compile this expression. So we need to write them by hand, and they're getting ugly:</p>
<pre>
implicit val Ugh1: Less[Val,Apply2Of3[Sum,Val,Add]#It] =
LeftLess[Val,Add](ValFunctor, AddFunctor)
implicit val Ugh2: Less[Add,Apply2Of3[Sum,Val,Add]#It] =
RightLess[Add,Add,Val](AddFunctor, AddFunctor, ValFunctor,
ReflLess[Add](AddFunctor))
</pre><p>Now I enjoy writing proofs as much as the next guy, but this is becoming pretty tedious... But in any case, now our definition of addExample2 works as expected, and we can write:</p>
<pre>
eval[Tmp](addExample2)
</pre><p>
So, this is a <em>little</em> better than the definition of addExample in the last post. If I needed to write code in this style, I'd certainly prefer this version. On the other hand, the necessary implicit definitions are much worse, and the improved syntax isn't nearly what we hoped for. I'd say we're at (or beyond) the limit of what we can do in Scala in this style.</p>
<p>What would it take to do better? Just a couple of things, from the last post, and a concrete challenge for each:</p>
<ul>
<li>Better inference for higher-kinded types. I want to be able to write the definition of addExample2 above with no type annotations inside the expression (of course I will have to annotate addExample2 itself).</li>
<li>Better inference of implicit conversions and parameters. I do not want to have to define Ugh1 or Ugh2 at all. These should be inferred from ReflLess, LeftLess and RightLess.</li>
</ul>
<p>There may be a completely different approach to this problem which is much more natural in Scala. But this approach should be possible as well, and Scala is very close to being able to express it very naturally. Implicits and inference need to be strengthened only a little bit.</p>
<p>Finally, just in case you were inclined to try getting the infix syntax with an implicit conversion... You might try:</p>
<pre>
trait Addable[F[_]] {
def |+|(x: Expr[F])(implicit fgLess: Less[Add,F]): Expr[F]
}
implicit def exprAddable[F[_]](f: Expr[F]): Addable[F] =
new Addable[F] {
def |+|(g: Expr[F])(implicit fgLess: Less[Add,F]): Expr[F] = inject[F,Add](Add(f,g))
}
val addExample3: Expr[Tmp] =
value[Tmp](30000) |+| value[Tmp](1330)
</pre><p>This seems reasonable, but we again receive the following incomprehensible error:</p>
<blockquote><p>
Tmp[_]'s type parameters do not match type F's expected parameters: type Tmp has one type parameter, but type F has one
</p></blockquote>
<p>So I'm forced to conclude that implicits basically can't be polymorphic in a higher-kinded type. This is frustrating, but it's not news. This is the same reason we have to annotate everything in addExample and addExample2: just another symptom of the lack of inference for these type constructors.</p>
http://matt.immute.net/content/hitting-wall#commentshaskellprogrammingscalaMon, 10 Mar 2008 14:42:56 -0500matt26 at http://matt.immute.netScala vs Skalleh
http://matt.immute.net/content/scala-vs-skalleh
<p>I apologize for what you're about to see...</p>
<p>As a little experiment, I decided to translate part of <a href="http://lambda-the-ultimate.org/node/2700">this pearl</a> from Haskell to Scala. By this I mean literal translation, as opposed to an idiomatic implementation in Scala. Of course, this goes deeply against the grain of the Scala language. On the other hand, as I wrote <a href="http://www.nabble.com/-scala--Bounds-in-higher-ranked-type-arguments-ts14681174.html#a15005781">here</a>:<br />
<blockquote>
It certainly cuts across the grain of current practice, and the grain of the libraries. But I think it takes a long time to discern the grain of a language. And I think it takes a lot of pushing and prodding, which is why I think this kind of experimentation is so important.</p>
<p>For now, it's a reasonable default to stick to a style that reflects the origins of the language (mostly Java-style OO with some functional goodies and richer types). I definitely think we should be open to the possibility that Scala style will diverge more radically from this tradition.
</p></blockquote>
<p>At this point, I'd probably replace the word "important" with "fun and maybe sort of worthwhile." Anyway, let's get started...<!--break--></p>
<p>I won't really explain what's going on. For that, please see the original paper. I'll only discuss the Scala novelties. First, a couple of terms, leaving the recursion open:</p>
<pre>
case class Val[E](i: Int)
case class Add[E](left: E, right: E)
</pre><p>Now the fixed point operator:</p>
<pre>
case class Expr[F[X]](e: F[Expr[F]])
</pre><p>You might think of this as a somewhat perverse way of making types like Val and Add subclasses of an as-yet-unknown Expr type. But we want to compose them, of course, so now we define the coproduct of types. In Haskell, we write:</p>
<pre>
data (f :+: g) e = (f e) :+: (g e)
</pre><p>In Scala, I call this Sum because it's shorter than Coproduct, although I realize it's easy to confuse it with Add.</p>
<pre>
sealed trait Sum[F[X], G[X], E]
case class Inl[F[X], G[X], E](l: F[E]) extends Sum[F,G,E]
case class Inr[F[X], G[X], E](r: G[E]) extends Sum[F,G,E]
</pre><p>Each of these is a functor, and we want to take advantage of this. So we'll need a simple functor trait. We encode type classes as traits, and instances as implicit instances:</p>
<pre>
trait Functor[F[X]] {
def map[A,B](f: A => B, t: F[A]): F[B]
}
</pre><p>And now we define the two obvious instances:</p>
<pre>
implicit object ValFunctor extends Functor[Val] {
def map[A,B](f: A => B, v: Val[A]): Val[B] =
Val(v.i)
}
implicit object AddFunctor extends Functor[Add] {
def map[A,B](f: A => B, v: Add[A]): Add[B] =
Add(f(v.left), f(v.right))
}
</pre><p>Now here's where things become severely unsatisfactory. In Haskell, we write:</p>
<pre>
instance (Functor f, Functor g) => Functor (f :+: g) where
...
</pre><p>But in Scala, Sum is not curried, and there's no easy way to partially apply it. So it's much more difficult. We need to use the following type-level combinator, and project out the type It (of the desired kind * -> *):</p>
<pre>
trait Apply2Of3[F[A[_],B[_],_],A[_],B[_]] {
type It[C] = F[A,B,C]
}
</pre><p>Note that this is a highly specialized combinator: the kinds of all arguments are fully known and annotated. This is unfortunate.</p>
<p>(Aside: in Haskell, we can just write</p>
<pre>
type Apply2 f a b = f a b
</pre><p>which is much more general. However, we can't seem to use this at multiple kinds in the same module. I don't know the name of this limitation in Haskell. If anyone knows, please enlighten me!)</p>
<p>Anyway, using Apply2Of3, we can show that coproducts are functors:</p>
<pre>
implicit def sumFunctor[F[_],G[_]](implicit ff: Functor[F],
gf: Functor[G]) =
new Functor[Apply2Of3[Sum,F,G]#It] {
type Tmp[X] = Apply2Of3[Sum,F,G]#It[X]
def map[A,B](f: A => B, v: Tmp[A]): Tmp[B] = v match {
case Inl(l) => Inl[F,G,B](ff.map(f, l))
case Inr(r) => Inr[F,G,B](gf.map(f, r))
}
}
</pre><p>We can fold over the fixed points of functors. By now, the type annotations are becoming pretty cumbersome:</p>
<pre>
def foldExpr[F[X],A](f: F[A] => A, expr: Expr[F])
(implicit functor: Functor[F]): A =
f(functor.map[Expr[F],A](foldExpr[F,A](f, _), expr.e))
</pre><p>
Evaluation is an algebra on a functor F. However, I don't actually require the Functor instance here, because it simplifies the translation. These are very similar to the above Functor definitions:</p>
<pre>
trait Eval[F[X]] {
def eval(f: F[Int]): Int
}
implicit object ValEval extends Eval[Val] {
def eval(v: Val[Int]): Int = v.i
}
implicit object AddEval extends Eval[Add] {
def eval(v: Add[Int]): Int = v.left + v.right
}
implicit def sumEval[F[_],G[_]](implicit fe: Eval[F],
ge: Eval[G]) =
new Eval[Apply2Of3[Sum,F,G]#It] {
type Tmp[X] = Apply2Of3[Sum,F,G]#It[X]
def eval(v: Tmp[Int]): Int = v match {
case Inl(l) => fe.eval(l)
case Inr(r) => ge.eval(r)
}
}
</pre><p>
With these definitions in hand, we can evaluate expressions:</p>
<pre>
def eval[F[_]](e: Expr[F])(implicit fe: Eval[F],
ff: Functor[F]) =
foldExpr[F,Int](fe.eval(_), e)
</pre><p>
Of course we want to test it. Here, things are horribly ugly. It's possible to make things a bit better with a temporary type alias, but even so, it's very unpleasant:</p>
<pre>
type Tmp[X] = Apply2Of3[Sum,Val,Add]#It[X]
val addExample: Expr[Tmp] =
Expr[Tmp](
Inr[Val,Add,Expr[Tmp]](
Add(
Expr[Tmp](Inl[Val,Add,Expr[Tmp]](Val(118))),
Expr[Tmp](Inl[Val,Add,Expr[Tmp]](Val(1219))))))
</pre><p>And unfortunately, Scala cannot figure out how to automatically apply the implicit conversions necessary to produce the following instances, so we need to write them down by hand. (I might add that the error messages are particularly incomprehensible if we try to have these inferred.)</p>
<pre>
implicit val ev = sumEval[Val,Add](ValEval, AddEval)
implicit val fc = sumFunctor[Val,Add](ValFunctor, AddFunctor)
</pre><p>
Finally:</p>
<pre>
def test = println("eval addExample: " +
eval[Tmp](addExample))
</pre><p>
That brings us through the end of section 3 of the paper. Wonderful! I take a few things from this little exercise:</p>
<ul>
<li>Fully curried definitions is the right default! This is not news, but over time, I've become more and more convinced of this.</li>
<li>No matter the default, we need to be able to define types with kinds like * -> * -> *, rather than just (*,*) -> *.</li>
<li>We would really like to be able to write kind-polymorphic types (like Apply2Of3, but as liberal as possible in the kinds of its arguments).</li>
<li>Scala's inability to infer types with kinds other than * is a pretty big problem.</li>
<li>Scala needs to be better at inferring implicit conversions and parameters.</li>
<li>Haskell syntax is amazingly sweet and elegant. This is also not news.</li>
<li>All told, it <em>is</em> possible to express these ideas in Scala.</li>
<li>I need to get some code highlighting going on this blog.</li>
</ul>
<p><strong>UPDATE:</strong> Continued in <a href="/content/hitting-wall">part 2</a>.</p>
http://matt.immute.net/content/scala-vs-skalleh#commentshaskellprogrammingscalaFri, 07 Mar 2008 13:30:06 -0600matt25 at http://matt.immute.net