I'm a Scala programmer learning Haskell with "Haskell Programming from First Principles" to give more coherence to the functional concept I'm using in Scala.
I understand the concept of currying pretty well. Implemented it in Scala well.
I do not understand however, the implementation of currying and uncurry provided by the author:
curry f a b = f (a, b)
:t curry
-- curry :: ((t1, t2) -> t) -> t1 -> t2 -> t
:t fst
-- fst :: (a, b) -> a
:t curry fst
-- curry fst :: t -> b -> t
uncurry f (a, b) = f a b
:t uncurry
-- uncurry :: (t1 -> t2 -> t) -> (t1, t2) -> t
(Page 134).
What is happening here?
In the first case, is it because of applying f (a, b) that we infer that f was actually ((t1, t2) -> t) but then what exactly turns it in t1 -> t2 -> t
I don't understand the inference and the overall curry/uncurry process.
Edit 1
From all the response given so far, i do get it now. I guess I am trying now to get the smart of Haskell.
Taking the curry example:
If I write the equivalent of how one would solve that in Scala, in Haskell:
myCurry :: ((a,b) -> c) -> a ->b -> c
myCurry f = \a -> \b -> f(a,b)
For reference, the Scala equivalent:
def curry[A,B,C](f: (A, B) => C): A => (B => C) = a => b => f(a, b)
Obviously this is not the idiomatic way to solve that in Haskell. I am interested in what's wrong with that solution from an Haskell point of view, so I can start getting a better sense of the of what makes the Haskell Type System so revered.
So far the only difference I see is that the idiomatic Haskell solution has a bit more inference going on and rely on the partial application of curry. The Scala solution require to be more explicit manual.
Not sure going through some mental gymnastics as such to understand something that simple, is that useful. But why not.
Edit 2
Actually found the way to do the same in Scala albeit minus the generic type all the way.
def fst[A, B](a: A, b:B): A = a
//fst: fst[A,B](val a: A,val b: B) => A
fst[Int, Int] _
//res0: (Int, Int) => Int
def sCurry[A,B,C](f: (A, B) => C) (a: A) (b: B) = f(a,b)
//sCurry: sCurry[A,B,C](val f: (A, B) => C)(val a: A)(val b: B) => C
sCurry[Int, Int, Int] _
//((Int, Int) => Int) => (Int => (Int => Int))
val s = sCurry(fst[Int, Int]) _
//s: Int => (Int => Int)
s (4) (2)
//res1: Int = 4