Why this works:
( ) <$> (*2) <*> (*2) $ 2
But this one doesn't?
( ) <$> (*2) <*> (*2) <*> (*2) $ 2
(error is: cannot construct the infinite type)
Yet this one does:
(\x y z -> x y z) <$> (*2) <*> (*2) <*> (*2) $ 2
Sorry if these are trivial questions, I'm in the journey of learning Haskell and want to make sure I understand it fully before moving on to the next topics.
CodePudding user response:
The type of ( )
is Int -> Int -> Int
(actually it is more general, but I will use the concrete type Int
for this example). So, it is a function that takes two integers as input.
The type of (\x y z -> x y z)
is Int -> Int -> Int -> Int
. So, it is a function that takes three integers as input.
These two functions are not interchangeable, because the types are not the same.
Perhaps your confusion stems from the unclear error message. If you actually write out the concrete type of ( )
like this:
ghci> (( ) :: Int -> Int -> Int) <$> (* 2) <*> (* 2 ) <*> (* 2) $ 2
Then you get a nicer error message:
<interactive>:7:1: error:
* Couldn't match type `Int' with `Int -> t'
Expected type: Int -> Int -> t
Actual type: Int -> Int
* Possible cause: `(<*>)' is applied to too many arguments
...
* Relevant bindings include it :: t (bound at <interactive>:7:1)
Still not very clear, but at least it mentions that the number of arguments is off.
CodePudding user response:
( )
is the same as (\x y -> x y)
, or if you had a really weird Num
instance in scope (\x y z -> (x y) z)
, which is not the same as (\x y z -> x y z)
. The simple explanation is that ( )
takes two arguments, and in your non-working snippet, you're trying to pass it three. Your third snippet works because you're using two
s instead of just one. Consider that ( ) 4 4
and ( ) (( ) 4 4) 4
are both valid, but that ( ) 4 4 4
is not.