2/8/09

Flavors of Curry: Scala vs Haskell


Scala is a nice language to explore functional programming, and for me it was easy to use it as a “stepping stone” and jump to Haskell with all the purity and laziness (I think is because I'm the kind of guy that enter slowly in the cold water...). I'm using Haskell to learn the theory and tools of functional programming (in a language that forces you to), so I can use them in Scala.

To that end, I'm going through “Learn You a Haskell for Great Good!” (I seem to have a fondness for technical books with silly images). Usually I'll try to do the same exercises in Scala to compare.

I was going through the chapter about higher order functions and currying. What are curried functions? You can find a very good explanation in wikipedia (of course!). Basically is the transformation of a function with multiple parameters into another function with only one parameter that returns a function of the remaining parameters. With that, your language can care only about functions with only one parameter and still be equally powerful. The advantage is if you call a function with less parameters, you get a partially applied function.

One of the examples on the “Learn you...” is a “flip” function: a function that exchanges the first and second parameter of a given function. In Haskell is as easy as:

flip1 f x y = f y x

That's all! Hindley-Milner type inference ensures the type safety:

flip1 :: (t1 -> t -> t2) -> t -> t1 -> t2

As an example:


f x y =x/y
f 1 2
0.5

g= flip1 f
g 1 2
2.0


BTW, there's something odd:


Prelude> let flip1 f x y = f y x
Prelude> :t flip1
flip1 :: (t1 -> t -> t2) -> t -> t1 -> t2
Prelude> let f x y =x/y
Prelude> :t f
f :: (Fractional a) => a -> a -> a
Prelude> let g=flip f
Prelude> :t g
g :: Double -> Double -> Double
Prelude> :t flip1 f
flip1 f :: (Fractional t1) => t1 -> t1 -> t1



The type of flip1 f is (Fractional t1) => t1 -> t1 -> t1, meaning that t1 is restricted to be of Fractional typeclass, but if I bind g to flip f, now the type is Double... that's not what one would expect! (Any Haskell expert can tell me what's happening?)


As usual, I'll tried to do the same in Scala to see how far it can goes.
The main difference is of course, type inference: in Scala you need to declare the function types. The other major difference is Haskell every function is curried by default, in Scala you need to explicitly curry the function by separating each parameter between parentheses.

In Scala, our (curried) f function will be:


def f(x:Int)(y:Int)=x/y
f: (Int)(Int)Int


The flip function in Scala would be:


def flip1[A,B,C]( f:A=>B=>C)(x:B)(y:A) =f(y)(x)
flip1: [A,B,C]((A) => (B) => C)(B)(A)C


Is clearly more verbose than the Haskell version, but equally powerful:


def g = flip1 (f) _
g: (Int) => (Int) => Int



The underscore is needed to get the partially applied function and the f must be in parentheses (again, all curried parameters must have their own parentheses).


Conclusion? Nothing. Haskell and Scala are obviously different, but they share some common ground... just wanted to show it :)
Post a Comment