I have a hard time to understand Currying in Haskell. I was not able to understand the already existing answers to this topic. I want to understand what the difference is between:
(Int -> Int) -> Int
and
Int -> (Int - > Int)
I think the answer has something to do with currying. I have already consulted some resources about the topic and I have got an idea.
Functions that have several parameters can be described as an array of elementary operations with one input and one output.
According to the online tutorial learnyouahaskell:
"Doing max 4 5 first creates a function that takes a parameter and returns either 4 or that parameter, depending on which is bigger. Then, 5 is applied to that function and that function produces our desired result."
So in this case the elementary basic operations are just comparing two values. And the first operation is
if "lowest value possible" > 4 then "lowest value possible" otherwise 4
The second operation is
if 4 > 5 then 4 otherwise 5
This would represent Int -> (Int -> Int) but what would (Int -> Int) -> Int be?
Int -> (Int -> Int)
is the same type as
Int -> Int -> Int
and is the type of a curried two-arguments function, both being integers. That is it is a function which takes an integer argument and returns a function, whose argument is another integer, and which finally returns an integer.
Possible calls are f 3 2 and f (7+4) (5*8).
Possible definitions are f a b = a+b and f a b = a*a+42*b.
Instead,
(Int -> Int) - > Int
is not a binary function, curried or not. It is a function with a single argument, and this argument is a function Int -> Int. The final result is an integer.
Possible calls are f (\x -> x+1), f id, and f g where g n = n*4+5.
Possible definitions are f h = h 45 and f h = h (h 6) + h 7 + 9.
The idea of partial function application is a hallmark of Haskell.
Exploiting partial application is natural. It is much how we think.
I fill my glass half with tea. Then I fill it completely with lemonaid.
m2 = max 4 --partial application (Int -> Int)
m2 5 -- full application (Int -> Int) -> Int
All functions in Haskell are curried. It is sometimes necessary to disable it with uncurry
m3 = uncurry max
m4 = m3 4 -- does not become (Int -> Int)
m4 3 -- is not (Int -> Int) -> Int -> Int
Does not work and the error has to do with partial application (Int -> Int) because the function now requires two parameters.
Related
Why it's possible to reduce function in Haskell:
calculate :: Integer -> Integer -> Integer
calculate a b = f 1 a b
where
f :: Integer -> Integer -> Integer -> Integer
f a b c = a + b
into something:
calculate :: Integer -> Integer -> Integer
calculate = f 1
where
f :: Integer -> Integer -> Integer -> Integer
f a b c = a + b
I just need some guidance, any resources where I can find the answer and read more about it would be really helpful.
In Haskell there are no functions that take more than one parameter. All functions take exactly one parameter.
So if you have a function like add :: Int -> Int -> Int, then this is actually short for add :: Int -> (Int -> Int).
Why are the brackets important? Because they show how this concept works. If we have this function add, then we can make a function application with for example 14, then we construct a new function, like:
add14 :: Int -> Int
add14 = add 14
so that means that we now have a function that takes again one parameter (here an Int), and now it will produce another Int, it does that by adding 14 to it, so add14 25 will result in 39.
If you write add 14 25, this thus is not a function application with two parameters, what you actually wrote is:
-- add 14 25 is equivalent to
(add 14) 25
You thus first make a call with 14, and the you make a call with the function that comes out of this, and 25 as the parameter.
Why is this important? Because it means that if you thus write
calculate = f 1
it means that your f 1, constructs a function, a function with signature Int -> (Int -> Int). Creating parameters in the head of calculate, and adding these to the end of f 1, thus makes no sense: you already constructed a function that takes such parameters anyway. So it only introduces noise.
In lambda calculus, the rewrite rule where one rewrites λ x . f x to just f is (and vice versa) is called η-conversion [wiki]. In Haskell it comes down to rewriting:
f x = g x
to:
f = g
Operators are no different. In fact if you write a + b in Haskell, you wrote (+) a b, with (+) a function, or more verbose ((+) a) b.
The f in the where clause:
f a b c = a + b
can for example get converted to:
f = (.) ((.) const) (+)
It's called eta reduction.
You might also think about it in terms of partial application.
> calculate :: Integer -> Integer -> Integer
> f :: Integer -> Integer -> Integer -> Integer
> (f 1) :: Integer -> Integer -> Integer
Similar question - What does eta reduce mean in the context of HLint
multiply :: Int -> Int -> Int
multiply a b = a * b
minus :: Int -> Int -> Int
minus a b = a - b
minus2 :: Int -> Int -> Int
minus2 a b = b – a
minus2 (multiply (minus 3 5) 7) 9
minus2 ((minus 3 5) * 7) 9
9 - ((minus 3 5) * 7)
9 - ((3 - 5) * 7)
9 - ((-2) * 7)
9 - (-14)
23
Running the line minus2 (multiply (minus 3 5) 7) 9
Do I have the correct order of evaluation that Haskell would use?
Still new with functional programming so I'm not sure if I have the "lazy evaluation" process correct.
You can test your hypothesis by replacing subexpressions by (error "x"), (error "y"), etc. Whichever error is evaluated first is the one to show up when you run the expression.
To the point, evaluation can proceed in any order the compiler wants it to, as long as it gets the correct answer. For example, it could optimize the entire expression to 23 and have no evaluation at all at runtime. It could evaluate the right side of arithmetic operators before the left side, except for subtraction. It could randomly decide at runtime which to evaluate first.
Ignoring that, for an explanation of how to manually do the work, see "How Lazy Evaluation Works in Haskell".
But how to manually figure it out is not the main point of this answer. Your question was what evaluation order Haskell would actually use, so this answer loosely intends to tell you the evaluation order your program uses when compiled with the compiler of your choice (ignoring some caveats that don't matter for basic understanding of evaluation order).
With some work, we can have Haskell tell us what order it evaluates in. If you're in school, you probably want to learn how to find the evaluation order manually without assistance so that you can do well on a test.
It's recommended that you only do this to check an answer you're confident in. You can also use it if you get stuck, but you should only read up until the point that you're stuck to see what the next step is and to make an educated guess about why that's the next step so that you can begin to learn what the rules are by experimenting. This, in combination with the above linked article, will help quite a bit.
To do this, we can expand upon Jonas Duregård's answer by using Debug.Trace's functions instead of error. Debug.Trace's functions can output things when something starts or stops being evaluated, so they're quite appropriate here:
import Debug.Trace
-- Show result
r :: String -> Int -> Int
r nm n = trace ("Result of " ++ nm ++ " is " ++ show n) n
-- Show evaluation of Int -> Int -> Int function
f :: String -> (Int -> Int -> Int) -> Int -> Int -> Int
f nm g a b = e nm $ g a b
-- Show evaluation of an Int
e :: String -> Int -> Int
e nm = r nm . trace ("Evaluating " ++ nm)
-- Show Int literal
i :: Int -> Int
i n = e (show n) n
multiply :: Int -> Int -> Int
multiply a b = e "multiply" $ (f "multiply's *" (*))
(e "multiply's a" a)
(e "multiply's b" b)
minus :: Int -> Int -> Int
minus a b = e "minus" $ (f "minus's -" (-))
(e "minus's a" a)
(e "minus's b" b)
minus2 :: Int -> Int -> Int
minus2 a b = e "minus2" $ (f "minus2's -" (-))
(e "minus2's b" b)
(e "minus2's a" a)
main :: IO ()
main = print $ minus2 (multiply (minus (i 3) (i 5)) (i 7)) (i 9)
Once you've solved the problem on paper, you can check your answer with the results of the above code run on GHC. It tells you what evaluation order your code uses when compiled with GHC.
You can alternatively run this through the Haskell compiler of your choice.
I am a Haskell beginner currently working through The Craft of Functional Programming 2nd Edition. One of the exercises in the book asks me to write an averageThree function, which I have did, and then a howManyAboveAverage function using the averageThree function.
I was a bit stuck on how to do this but I found a similar problem here. I used the solution given in my code however I am getting a parse error [FIXED].
Here is my new code:
averageThree :: Int -> Int -> Int -> Float
averageThree a b c = fromIntegral (a + b + c) / 3
howManyAverageThree :: Int -> Int -> Int -> Int
howManyAverageThree a b c = length $ filter (> avg) the_three
where avg = averageThree a b c
the_three = fromIntegral <$> [a,b,c]
EDIT: New Error
Error trace:
[1 of 1] Compiling Main ( average.hs, interpreted )
average.hs:7:36: Not in scope: `<$>'
Failed, modules loaded: none.
I use ghci version 7.6.3 for compilation. Since I'm following a textbook example I need to preserve the function signatures. How can I modify this code such that I no longer get the above error?
In Haskell, indentation does matter. You need to match the indentation in your where clause:
howManyAverageThree :: Int -> Int -> Int -> Int
howManyAverageThree a b c = length $ filter (> avg) the_three
where avg = averageThree a b c
the_three = fromIntegral[a b c]
EDIT:
Following your edit to the question, you need to look more closely at the definition of the_three:
the_three = fromIntegral[a b c]
fromIntegral has type :: (Integral a, Num b) => a -> b
If you want to the_three to be a list of numbers, you need to do a few things.
First, your list constructions needs ,'s inside it. Second, you need to map fromIntegral over each element of that list.
import Control.Applicative((<$>))
....
the_three = fromIntegral <$> [a,b,c]
I learn Haskell.
This is not an operator, because an operator must to have two parameters:
(###) :: Int -> Int -> Int -> Int
(###) a b c = a + b + c
But what about this case:
(###) :: Int -> Int -> (Int -> Int)
(###) a b = \c -> a + b + c
This function has two parameters, but returns a function... Is it an operator now? I think it is not an operator still, because second variant is partial applied first. But I am not sure I am right. Can operator return a function?
There is no rule that says an operator has to have two parameters and in fact, semantically all functions in Haskell only ever take a single parameter. Your two examples are exactly identical as the type Int -> Int -> Int -> Int is implicitly bracketed as Int -> (Int -> (Int -> Int)).
You can use your operator like this
(1 ### 2) 3
or
1 ### 2 $ 3
I want to know whether shift is a higher order function or not.
chartoInt :: Char -> Int
chartoInt c = ord c
Inttochar :: Int -> Char
Inttochar n = chr n
shift :: Int -> Char -> Char
shift n c = Inttochar (chartoInt c + n)
None of these functions are higher order functions, because none of these functions take a function as a parameter.
shift's parameters are n (an Int) and c (a Char): neither are functions.
(Also: Inttochar should be inttochar: function names in Haskell cannot start with an upper case letter.)
Here's a higher order function that looks like your shift:
higherShift :: (Int -> Char) -> Int -> Char -> Char
higherShift f n c = f (chartoInt c + n)
shift = higherShift inttochar -- same as your original shift
Or, perhaps more usefully:
anotherHigherShift :: (Int -> Int) -> Char -> Char
anotherHigherShift f c = inttochar (f (chartoInt c))
shift n = anotherHigherShift (+n) -- same as your original shift
You can read the type signature for anotherHigherShift as saying that
it's a function
whose first parameter is a function (this function takes an Int and returns an Int)
whose second parameter is a Char
and which returns a Char
(+n) is shorthand for \m -> m + n.
It is.
The shift is a higher order function.
shift :: Int -> (Char -> Char) -- The long prototype.
It get Int and return function getting Char and returning Char.
P.S.
You should write inttochar.
There is informal rule: take a look at function's type. If it contains (with necessity [1]) braces, than it's a higher order function.
[1] In the meaning that omitting them changes the type.
And now take a look at types of your function and functions from first answer from this point of view. It's simple.