Number of arguments in Haskell code and type is different, why? - haskell

Can anybody explain the code below, what it does step by step, please. I know it is defining a function and its inputs, but what does (+) do, and why are there three Ints in plus and four Ints in plusplus's type, while it seems like there are only 3 arguments in plusplus's code?
plus :: Int -> Int -> Int
plus = (+)
plusPlus :: Int -> Int -> Int -> Int
plusPlus a b c = a + b + c

+ is the addition operator. Putting an operator in parentheses, like (+), refers to the addition function itself, as opposed to using + to add two numbers right on the spot. Basically, this:
plus = (+)
is equivalent to:
plus a b = a + b
Either way, it is defining plus to be a synonym for +.
In Haskell, -> is used to separate the types of the arguments, as well as the return value. So,
plus :: Int -> Int -> Int
is a function which takes two Ints and returns an Int.
plusPlus :: Int -> Int -> Int -> Int
is a function which takes three Ints and returns an Int.
The reason why the syntax is the same for the arguments and the return value is due to currying.
To be really pedantic,
plus :: Int -> Int -> Int -- ~ Int -> (Int -> Int)
is a function which takes an Int, and returns a function which takes an Int and returns an Int.
plusPlus :: Int -> Int -> Int -> Int -- ~ Int -> (Int -> (Int -> Int))
is a function which takes an Int, and returns a function which takes an Int, and returns a function which takes an Int and returns an Int.
In practice, it's convenient to speak of Haskell functions as taking multiple arguments. But technically, Haskell functions always take one argument. The argument type is on the left side of ->, and the return type is on the right side of ->, but the return type might itself be another function.

Related

Strict type alias in Haskell

Suppose I have a recursive function taking 3 integers, each having a different meaning, e.g.
func :: Int -> Int -> Int -> SomeType1 -> SomeType2
What I want is to prevent myself from mistyping the order of the arguments like this (somewhere in the func implementation):
func a b c t = f b a c ( someProcessing t )
The easiest way I've come up with is to define type aliases like
type FuncFirstArg = Int
type FuncSecondArg = Int
type FuncThirdArg = Int
And change func signature:
func :: FuncFirstArg -> FuncSecondArg -> FuncThirdArg -> SomeType1 -> SomeType2
But it seems like this approach doesn't work as I intended. Why does Haskell still allow me to pass FuncSecondArg as a first argument and so on. Is there a way to do what I want without declaring datatypes?
type in Haskell is a rename of an existing type. Just like String and [Char] are fully exchangeable, so are FuncFirstArg and Int, and by transition FuncSecondArg as well.
The most normal solution is to use a newtype which was introduced exactly for the purpose of what you try to achieve. For convenience, it is good to declare it as a record:
newtype FuncFirstArg = FuncFirstArg {unFuncFirstArg :: Int}
Note that newtype is entirely reduced during compilation time, so it has no overhead on the runtime.
However, if you have many arguments like in your example, a common strategy is to create a dedicated type for all of the parameters supplied to the function:
data FuncArgs = FuncArgs
{ funcA :: Int
, funcB :: Int
, funcC :: Int
, funcT :: Sometype1
}
f :: FuncArgs -> Sometype2
Yes, it has some bad impact on currying and partial application, but in many cases you can deal with it by providing predefined argument packs or even uncurry the function:
defaultArgs :: Sometype1 -> FuncArgs
defaultArgs t = FuncArgs {a = 0, b = 0, c = 0, t = t}
fUnc :: Int -> Int -> Int -> SomeType1 -> SomeType2
fUnc a b c t = f $ FuncArgs a b c t
Conclusion
For the typechecker to distinguish types, the types have to be actually different. You can't skip defining new types, therefore.

Type signatures are only allowed in patterns with ScopedTypeVariables - using where without curly braces

I am facing the following problem.
When I am trying to compile the function
myFunction :: Int -> Int -> Int
myFunction x y = myVar1
where {myVar1 :: Int;
myVar1 = 1}
everything works fine. However, when I am not using the curly braces and trying to indentate properly
myFunction :: Int -> Int -> Int
myFunction x y = myVar1
where myVar1 :: Int
myVar1 = 1
I get the error
Illegal type signature: `Int myVar1'
Type signatures are only allowed in patterns with ScopedTypeVariables
Could anyone please tell me why that is?
Thanks in advance
You are mixing tabs and spaces, indeed, if we work with Unicode's control pictures, we see:
myFunction :: Int -> Int -> Int
myFunction␣x␣y␣=␣myVar1
␣␣␣␣␣where␣myVar1␣::␣Int
␉␣␣␣␣␣␣␣myVar1␣=␣1
Notice the horizontal tab (␉) at the left side. Mixing tabs and spaces will very often result in compiler errors, since in this specific case, the Haskell compiler sees this as a type myVar1 :: Int myVar1, and hence the error.
You thus should only use spaces, like:
myFunction :: Int -> Int -> Int
myFunction x y = myVar1
where myVar1 :: Int
myVar1 = 1
where if we use control pictures, we only see spaces and the column matches whith that of the myVar1 :: Int part.
myFunction :: Int -> Int -> Int
myFunction␣x␣y␣=␣myVar1
␣␣␣␣␣where␣myVar1␣::␣Int
␣␣␣␣␣␣␣␣␣␣␣myVar1␣=␣1

Syntax in Functions (Expected kind `* -> Constraint', but `Int' has kind `*') [duplicate]

This question already has answers here:
`String' is applied to too many type arguments
(2 answers)
Closed 2 years ago.
I'm starting to learn Haskell and I'm struggling with syntax in Functions. I'm trying to create a function that receives a Number 'e' and a Number 'n', returning a list with of 'n' times 'e'.
Example: repn 3 5 would return [3,3,3,3,3]:
repn :: Int a => a -> a -> [a]
repn e n
| n >= 1 = (take n (repeat e))
| otherwise = []
But I'm getting this error:
* Expected kind `* -> Constraint', but `Int' has kind `*'
* In the type signature: replica :: Int a => a -> a
As a rule of thumb, writing something of the form Foo a => ... only makes sense of Foo is a type class. Unlike in OO languages, a class and a type in Haskell are completely different things. Int is a type, therefore it cannot be used in this way; instead you should simply use
repn :: Int -> Int -> [Int]
...though actually there's no reason to restrict the list-element type at all, the signature could as well be
repn :: a -> Int -> [a]
Alternatively, you can use a type class: the class of “int-like types” is Integral. Then you can't use take directly, as that is restricted to Int for the counter argument; however you can convert any integral type to Int:
repn :: Integral n => a -> n -> [a]
repn e n = take (fromIntegral n) $ repeat e
-- Note no case distinction is needed, because `take` already yields
-- an empty list if `n<1`.
Your type definition is not correct. The double arrow is used to show required typeclasses (aka kind * -> Constraint), or a constraint on types. However, Int is itself a type (aka kind *).
You can't specify types in this way. In your implementation, n must be an Int, but e could be anything. Since you specify that it should be a number, though, you can constrain it with the Num typeclass. The correct version of your signature therefore is:
repn :: Num a => a -> Int -> [a]
If you want e to be constrained to an Int, then your signature should be
repn :: Int -> Int -> [Int]
If you don't need any constraints on e, your signature can be
repn :: a -> Int -> [a]
These are all valid type signatures for the function you have written. (Though in actual code, I would just point you to the builtin replicate function.)

Finding out lambda calculus/haskell type of some example

Suppose that the function gets as its input two variables of different types (e.g. one variable is int in the language of C, and one variable is char in the language of C) and returns one variable that is in Int.
If this function is coded as Haskell or lambda calculus code, how would the function's type be?
So suppose that the function has type Int -> (Char -> Char) -> Int. What would this mean? Would this mean that it receives int variable as input and runs function of (Char -> Char) and outputs Int variable?
A type of Int -> (Char -> Char) -> Int would mean the function accepts an Int and a function of type Char -> Char as input, and outputs an Int.
The function doesn't have to actually use its inputs per se. For example,
meetoosFunction :: Int -> (Char -> Char) -> Int
meetoosFunction _ _ = 42
*Main Data.Char> meetoosFunction 1 toUpper
42

How to declare function (type misunderstanding Maybe)

I need a function which works like:
some :: (Int, Maybe Int) -> Int
some a b
| b == Nothing = 0
| otherwise = a + b
Use cases:
some (2,Just 1)
some (3,Nothing)
map some [(2, Just 1), (3,Nothing)]
But my code raise the error:
The equation(s) for `some' have two arguments,
but its type `(Int, Maybe Int) -> Int' has only one
I don't understand it.
Thanks in advance.
When you write
foo x y = ...
That is notation for a curried function, with a type like:
foo :: a -> b -> c
You have declared your function to expect a tuple, so you must write it:
some :: (Int, Maybe Int) -> Int
some (x, y) = ...
But Haskell convention is usually to take arguments in the former curried form. Seeing funcitons take tuples as arguments is very rare.
For the other part of your question, you probably want to express it with pattern matching. You could say:
foo :: Maybe Int -> Int
foo Nothing = 0
foo (Just x) = x + 1
Generalizing that to the OP's question is left as an exercise for the reader.
Your error doesn't come from a misunderstanding of Maybe: The type signature of some indicates that it takes a pair (Int, Maybe Int), while in your definition you provide it two arguments. The definition should thus begin with some (a,b) to match the type signature.
One way to fix the problem (which is also a bit more idiomatic and uses pattern matching) is:
some :: (Int, Maybe Int) -> Int
some (a, Nothing) = a
some (a, Just b) = a + b
It's also worth noting that unless you have a really good reason for using a tuple as input, you should probably not do so. If your signature were instead some :: Int -> Maybe Int -> Int, you'd have a function of two arguments, which can be curried. Then you'd write something like
some :: Int -> Maybe Int -> Int
some a Nothing = a
some a (Just b) = a + b
Also, you might want to add the following immediate generalization: All Num types are additive, so you might aswell do
some :: (Num n) => n -> Maybe n -> n
some a Nothing = a
some a (Just b) = a + b
(I've violated the common practice of using a, b, c... for type variables so as not to confuse the OP since he binds a and b to the arguments of some).

Resources