Haskell, error unwrapping Maybe Int - haskell

I wrote code:
is3 :: Int -> Maybe Int
is3 x = is3temp 0 x
is3temp :: Int -> Int -> Maybe Int
is3temp p x = if (abs p*p*p) < (abs x) then (is3temp (p+(signum x)) x) else (if p*p*p == x then (Just p) else Nothing)
c :: Maybe Int -> Int
c (Just x) = 2*x+1
c Nothing = 0
--fun::Int -> Int
--fun = c.is3
c1:: Int -> Int
c1 x = 2*x +1
c1 0 = 0
fun::Int -> Int
fun x = (is3 x) >>= c1
As you can see is3 takes Int and returns Maybe Int.
In fun I take result from is3 unwrap it and try to send it to c1.
And get error
ERROR file:1627.hs:47 - Type error in application
*** Expression : is3 x >>= c1
*** Term : c1
*** Type : Int -> Int
*** Does not match : a -> b c
What is wrong here?

Let's inspect all types that come together in is3 x >>= c1:
x :: Int
is3 :: Int -> Maybe Int
c1 :: Int -> Int
||| /???\
is3 x :: Maybe Int ||| ???????
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
(>>=) is3 x :: (Int -> Maybe b) -> Maybe b
is3 x >>= c1 :: $!%&/#?
As you can see, c1 doesn't work as right hand side of >>=, since it's return type is wrong. It must return some kind of Maybe. One can easily fix this with return . c1:
return . c1 :: Int -> Maybe Int
or with fmap, since the monad laws dictate that both must have the same effect:
fmap c1 :: Maybe Int -> Maybe Int
fmap c1 (is3 x) :: Maybe Int
However, this will also change fun's type. That being said, your functions name are rather bad and c1 is probably a typo (if fun's type is correct). It's possible that you actually wanted to use c:
fun :: Int -> Int
fun x = c (is3 x)

Some code that compiles:
is3 :: Int -> Maybe Int
is3 x = is3temp 0 x
is3temp :: Int -> Int -> Maybe Int
is3temp p x = if (abs p*p*p) < (abs x) then (is3temp (p+(signum x)) x) else (if p*p*p == x then (Just p) else Nothing)
c1 :: Int -> Int
c1 0 = 0
c1 x = 2*x +1
fun :: Int -> Maybe Int
fun = (fmap c1) . is3
I changed the type of fun from Int -> Int to Int -> Maybe Int, and am using fmap instead of >>=.
Also I flipped the order of the matches in c1. Matches are applied top to bottom, so the 0 case never would have applied in the order you have it.

Related

Can't understand result when calling applyTwice multiple times

There are many questions based on applyTwice, but none that relate to my problem. I understand that the applyTwice function defined like this:
applyTwice :: (a -> a) -> a -> a
applyTwice f a = f (f a)
applies a function twice. So if I have an increment function:
increment x = x + 1
and do
applyTwice increment 0
I get 2. But I don't understand these results:
applyTwice applyTwice applyTwice increment 0 -- gives 16
applyTwice applyTwice applyTwice applyTwice increment 0 -- gives 65536
applyTwice applyTwice applyTwice applyTwice applyTwice increment 0 -- stack overflow
I also know that
twice = applyTwice applyTwice increment
applyTwice twice 0 -- gives 8
I simply cannot wrap my head around these results, would love it if someone could explain. I apologize if this is something basic, as I'm just learning Haskell.
Let's use the informal notation
iter n f = f . f . f . .... -- n times
Your applyTwice is then simply iter 2.
From the definition, we immediately get:
(iter n . iter m) f
= iter n (iter m f)
= (f.f. ...) . ... . (f.f. ...) -- n times (m times f)
= iter (n*m) f
hence, eta contracting,
iter n . iter m = iter (n*m) -- [law 1]
We also have
iter n (iter m)
= -- definition
iter m . iter m . .... . iter m -- n times
= -- law 1
iter (m*m* ... *m) -- n times
= -- power
iter (m^n) -- [law 2]
We then have, writing t for applyTwice:
t = iter 2
t t
= -- previous equation
iter 2 (iter 2)
= -- law 2
iter (2^2)
t t t
= -- left associativity of application
(t t) t
= -- previous equation
iter (2^2) (iter 2)
= -- law 2
iter (2^(2^2))
t t t t
= -- left associativity of application
(t t t) t
= -- previous equation
iter (2^(2^2)) (iter 2)
= -- law 2
iter (2^(2^(2^2)))
and so on.
There is a lot of complexity hiding behind the scenes in the form of invisible type arguments. What happens if we write these arguments out with -XTypeApplications. I have shortened some of the names.
The following twice is instantiated at twice #Int whose type is second-order.
one :: Int
one = twice (+ 1) 0
^^^^^
|
twice #Int
:: (Int -> Int)
-> (Int -> Int)
When you apply twice (order-3) to twice (order-2) the type signature becomes more complicated.
two :: Int
two = twice twice (+ 1) 0
^^^^^ ^^^^^
| |
| twice #Int
| :: (Int -> Int)
| -> (Int -> Int)
|
twice #(Int->Int)
:: ((Int->Int) -> (Int->Int))
-> ((Int->Int) -> (Int->Int))
And so forth, when you have twice twice twice they are order-4, order-3 and order-2 respectively:
three :: Int
three = twice twice twice (+ 1) 0
^^^^^ ^^^^^ ^^^^^
| | |
| | twice #Int
| | :: (Int -> Int)
| | -> (Int -> Int)
| |
| twice #(Int->Int)
| :: ((Int->Int) -> (Int->Int))
| -> ((Int->Int) -> (Int->Int))
|
twice #((Int->Int)->(Int->Int))
:: (((Int->Int)->(Int->Int)) -> ((Int->Int)->(Int->Int)))
-> (((Int->Int)->(Int->Int)) -> ((Int->Int)->(Int->Int)))
the last example you gave becomes this monstrosity with order-6, order-5, order-4, order-3, order-2 respectively...
{-# Language TypeApplications #-}
five :: Int
five = twice #((((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int)))->(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
(twice #(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
(twice #((Int->Int)->(Int->Int)))
(twice #(Int->Int))
(twice #Int)
(+ 1) 0
So this is the type of the first twice!!
twice #((((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int)))->(((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))))
:: (((((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> (((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int)
-> (Int -> Int)
-> Int
-> Int)
-> ((((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> (((Int -> Int) -> Int -> Int) -> (Int -> Int) -> Int -> Int)
-> ((Int -> Int) -> Int -> Int)
-> (Int -> Int)
-> Int
-> Int

How to pass not a function that returns a boolean in another function?

I want to negate a function in the if clause of another function like bellow:
isBig :: Integer -> Bool
isBig n = n > 9999
function :: Integer -> Integer
function n =
if not isBig n then ... else ...
It complies when it's just 'if isBig n then else' but I'm not sure why it doesn't work for 'not isBig' as I get this error:
*Couldn't match expected type Bool' with actual type Integer -> Bool'
Many thanks in advance.
You want not (isBig n). not isBig n tries to pass two arguments to not, both isBig and n. isBig is an Integer -> Bool but a Bool is expected, hence the error.
In general, function application in Haskell is left-associative, meaning that an expression like this:
f 2 3 5
Is parsed like this:
(((f 2) 3) 5)
Likewise, the arrows in function types are right-associative, so for example if we had this definition for f:
f :: Int -> Int -> Int -> Int
f x y z = x * y + z
That type signature is the same as:
f :: Int -> (Int -> (Int -> Int))
So it looks like this as you apply more arguments:
f :: Int -> (Int -> (Int -> Int))
(f 2) :: (Int -> (Int -> Int))
((f 2) 3) :: (Int -> Int)
(((f 2) 3) 5 :: Int
==
f :: Int -> Int -> Int -> Int
f 2 :: Int -> Int -> Int
f 2 3 :: Int -> Int
f 2 3 5 :: Int
When you’re applying a chain of functions to an argument, you end up with parentheses associating to the right:
f (g (h x))
In this case it’s common to use the $ operator, which is right-associative and has low precedence, just to reduce the nesting of brackets:
f $ g $ h x
And you can do so in your case: not $ isBig n
You can also use composition to factor out the chain of functions and apply it to different arguments elsewhere:
fgh = f . g . h
fgh x
==
(f . g . h) x
==
f (g (h x))
isNotBig = not . isBig
isNotBig n
==
(not . isBig) n
==
not (isBig n)

How to return different type in recursion function? (Haskell)

I need to return for example either an integer or a Boolean in a recursive function.
An example code of my problem:
findInt :: [Int] -> Either Int Bool
findInt (x:xs) =
if x == 1 then x
else False : findInt xs
Then the error says couldn't match expected type "Either Int Bool" with actual type "Int". But I want to check whether the element is in this list and if it does it will return the element and tell me if it's not by returning a Boolean.
If you have a look at the Either type, you'll see that it has two constructors, Left and Right. In order to construct a value of the Either type, you need to use one of the constructors. e.g.
if x == 1 then Left x
Specifically, Left is used to construct the first type of the Either type (Int in this case), and Right is used for the second type (Bool in this case).
Your function as given has no type: x :: Int and (False : _) :: [Bool], and these two types can't be unified (read :: as "has a type").
Tweaked,
findInt (x:xs) =
if x == 1 then Left x
else Right False : findInt xs
it still has no type: Left x :: Either Int b and (Right False : _) :: [Either a Bool], and these two types can't be unified either.
But
findInt :: [Int] -> Either Int Bool
findInt (x:xs) =
if x == 1 then Left x
else findInt xs
findInt [] = Right False
has a type, because Left x :: Either Int b and Right False :: Either a Bool, and these two types can be unified:
Either Int b
Either a Bool
----------------- a ~ Int , b ~ Bool
Either Int Bool
The unified type is indeed Either Int Bool, as the type signature specifies.
Since you never use True in your output, your use of Either Int Bool is isomorphic to Maybe Int:
a2b :: Either Int Bool -> Maybe Int
a2b (Right x) = Just x
a2b (Left x) = Nothing
b2a :: Maybe Int -> Either Int Bool
b2a (Just x) -> Right x
b2a Nothing -> Left False
As such, I would just use Maybe Int to simplify your function.
findInt :: [Int] -> Maybe Int
findInt [] = Nothing
findInt (x:xs) = if x == 1 then Just x else findInt xs

Interpreting Haskell monad example

I have this Haskell code that triples input value.
triple :: Int -> Int
triple = do
n <- id
d <- (n+)
(d+)
How does this code work? With an example triple 10, how the argument 10 is mapped/assigned to id, n and d to get the return value of 30?
My understandig is as follows:
We can decompose triple function with two subfunctions tripleA and tripleB as follows:
triple :: Int -> Int
triple = tripleA >>= (\d -> tripleB d)
tripleA :: Int -> Int
tripleA = id >>= (\n -> (n+))
tripleB :: Int -> Int -> Int
tripleB d = (d+)
Now we can see that the function tripleA gets an input, assign it to id function to return the value itself, and map it to the function (\n -> (n+)) to return (10+) 10.
Likewise, tripleB also makes (20+) 20, so I expect the results as 40, but the correct answer is 30.
What is wrong with my interpretation?
We can rewrite equivalent triple2 function as follows:
triple2 = (id >>= (\n -> (n+))) >>= (\d -> (d+))
With f = \n -> (n+), we have triple2 = (id >> f) >> f.
From the definition of >>= in (https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-645), we have
1. id >>= f
\r -> f (id r) r = \r -> f r r = \r -> (r+) r
2. (id >>= f) >>= f
x = id >>= f = \r -> (r+) r
x r = (r+) r
x >> f = \r -> f (x r) r = f ((r+) r) r = ((r+) r)+ r
so ((10+) 10)+ 10 makes 30

Understanding Haskell Pattern Matching

Using pattern matching, define a function:
ifThenElse :: Bool -> Int -> Int -> Int
which gives its second argument if the condition (the first argument) is True, and the
third argument if the condition is False (for example, ifThenElse (3 > 5) 7 12 gives
12).
How would I go about writing this?
Here is what I have so far:
ifThenElse :: Bool -> Int -> Int -> Int
ifThenElse True x1 y1 = x1
ifThenElse False x1 y1 = y1
Here is a hint.
You can solve your problem using if-else statement:
ifThenElse :: Bool -> Int -> Int -> Int
ifThenElse p x y = if p then x else y
But, Bool is enumerated type with only two values. You can match ifThenElse's arguments with Bool values and define what to do if function gets False or True. It's called pattern-matching:
ifThenElse :: Bool -> Int -> Int -> Int
ifThenElse False = ...
ifThenElse True = ...
And at last, if you use pattern-matching and in some case resulting value doesn't depend from particular argument, you can hide that argument using placeholder:
f :: Int -> Int -> Int -> Int
f 0 x y = x + y
f 1 _ y = y -- in case of getting `1` function returns just `y`

Resources