Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we show multiple arguments with arrows and the return type with an arrow?

For example in the Elm basics docs:

(/) : Float -> Float -> Float

This is saying that / is a function which takes a float, and another float and returns a float.

Why wouldn't it be like:

(/) : (Float, Float) -> Float

For example, which seems to be more intiutive.

Is there a special reason for this? This is also how types are annotated in Haskel also.

https://package.elm-lang.org/packages/elm/core/latest/Basics

EDIT: This has been answered, but I also found this in the documentation for Elm: https://guide.elm-lang.org/appendix/function_types.html

like image 475
Craig Harley Avatar asked Oct 01 '19 14:10

Craig Harley


2 Answers

Technically Elm does not have functions of more than one argument. The type Float -> Float -> Float (which is the same as Float -> (Float -> Float) because -> is right-associcative) represents a function that takes a Float and returns another function that takes another float. Then a call like (/) a b (which is the same as ((/) a) b because function application is left-associative) first applies the function (/) to a and then applies the resulting function to b.

Note that you can also just apply / to a single argument without applying the result to a second argument right away: For example inv = (/) 1 would define an inv function that acts the same as inv x = 1 / x.

(Float, Float) -> Float would be the type of a function that takes a tuple containing two floats. You could define a function with that type like this:

f: (Float, Float) -> Float
f (x,y) = ...

And then you could call it as f (arg1, arg2) where arg1 and arg2 are floats or f tup where tup is a tuple of two floats.

like image 77
sepp2k Avatar answered Nov 15 '22 11:11

sepp2k


In functional programming it's easier to use version which returns other functions so when you see (/) : Float -> Float -> Float it means that you can pass one argument and get the function Float -> Float back. So effectively there is no difference in the result (assuming that you pass both arguments).

This technique of going from tuple version (uncurried) to functional version (curried) is called currying and is widely used and will become intuitive after practice. I'm not familiar with elm but in Haskell you can easily go from curried version and back:

f :: a -> (b -> c)     -- (which can also be written as    f :: a -> b -> c )
g :: (a, b) -> c

f = curry g -- transform argument from tuple to functions
g = uncurry f -- transform function arguments to tuple

So if you apply the function f to only one argument you get back a function which can be re-used. Check the Haskell wiki for more details. In contrary with function which expect tuple the re-usability will be limited. Check also the Partial application section of the wiki to understand why it's important.

add2 :: Integer -> Integer -> Integer
add2 a b = a + b

add5 :: Integer -> Integer
add5 b = add2 5 b -- add2 is re-used
like image 25
Izbassar Tolegen Avatar answered Nov 15 '22 11:11

Izbassar Tolegen