Haskell Let Expressions Evaluation - haskell

I am doing practice problems that evaluate a let expression and I don't understand the output of this one.
Here is the expression:
let a = 2
b = 1:[i * 2 | i <- b]
f a = 1:[i * a | i <- (f a)]
in take (a+2) (f (head (tail b) ))
The output is supposed to be [1,2,4,8]. Could someone please explain step by step why this is the output

Here's a step-by-step explanation:
let a = 2
b = 1:[i * 2 | i <- b]
f a = 1:[i * a | i <- (f a)]
in take (a+2) (f (head (tail b) ))
There's two different variables called a in there, and one shadows the other, so first let's rename one of them to avoid accidentally mixing them up:
let outer_a = 2
b = 1:[i * 2 | i <- b]
f a = 1:[i * a | i <- (f a)]
in take (outer_a+2) (f (head (tail b) ))
Now we can substitute in outer_a and evaluate the +:
let b = 1:[i * 2 | i <- b]
f a = 1:[i * a | i <- (f a)]
in take 4 (f (head (tail b) ))
Rewrite the list comprehensions in terms of map:
let b = 1:map (* 2) b
f a = 1:map (* a) (f a)
in take 4 (f (head (tail b) ))
Use iterate instead of explicit recursion:
let b = iterate (* 2) 1
f a = iterate (* a) 1
in take 4 (f (head (tail b) ))
Evaluate the first two steps of b:
let b = 1:2:iterate (* 2) 4
f a = iterate (* a) 1
in take 4 (f (head (tail b) ))
Substitute in b:
let f a = iterate (* a) 1
in take 4 (f (head (tail (1:2:iterate (* 2) 4)) ))
Evaluate tail:
let f a = iterate (* a) 1
in take 4 (f (head (2:iterate (* 2) 4) ))
Evaluate head:
let f a = iterate (* a) 1
in take 4 (f 2)
Substitute in f a:
take 4 (iterate (* 2) 1)
Evaluate iterate a few times:
take 4 (1:2:4:8:iterate (* 2) 16)
Evaluate take:
[1,2,4,8]
And we're done.

To see what's going on we carefully name each entity as it comes into being:
let a = 2
b = 1 : [i * 2 | i <- b]
f a = 1 : [i * a | i <- f a]
in take (a+2) (f (head (tail b)))
==
let b = (b1:bs1)
(b1:bs1) = 1 : [i * 2 | i <- b]
in take 4 (f (head (tail b)))
==
let b1 = 1
bs1 = [i * 2 | i <- (b1:bs1)]
in take 4 (f (head bs1))
==
let b1 = 1
bs1 = [i * 2 | i <- [b1]] ++ [i * 2 | i <- bs1]
in take 4 (f (head bs1))
==
let bs1 = [i * 2 | i <- [1]] ++ [i * 2 | i <- bs1]
in take 4 (f (head bs1))
==
let bs1 = (b2:bs2)
(b2:bs2) = [1 * 2] ++ [i * 2 | i <- bs1]
in take 4 (f b2)
==
let (b2:bs2) = 2 : [i * 2 | i <- (b2:bs2)]
in take 4 (f b2)
==
let bs2 = [i * 2 | i <- (2:bs2)]
f a = 1 : [i * a | i <- f a] -- same as before
in take 4 (f 2)
==
let xs = f 2
f 2 = 1 : [i * 2 | i <- f 2]
in take 4 xs
==
let (x1:xs1) = 1 : [i * 2 | i <- f 2]
in take 4 (x1:xs1)
==
let xs1 = [i * 2 | i <- f 2]
in take 4 (1:xs1)
==
let xs1 = [i * 2 | i <- f 2]
in 1 : take 3 xs1
==
let (x2:xs2) = [i * 2 | i <- (y1:ys1)]
(y1:ys1) = 1 : [i * 2 | i <- f 2]
in 1 : take 3 (x2:xs2)
==
let (x2:xs2) = [i * 2 | i <- (1:ys1)]
ys1 = [i * 2 | i <- f 2]
in 1 : take 3 (x2:xs2)
==
let (x2:xs2) = 2 : [i * 2 | i <- ys1]
ys1 = [i * 2 | i <- f 2]
in 1 : take 3 (x2:xs2)
==
let xs2 = [i * 2 | i <- ys1]
ys1 = [i * 2 | i <- f 2]
in 1 : take 3 (2:xs2)
==
let xs2 = [i * 2 | i <- ys1]
ys1 = [i * 2 | i <- f 2]
in 1 : 2 : take 2 xs2
==
let (x3:xs3) = [i * 2 | i <- (y2:ys2)]
(y2:ys2) = [i * 2 | i <- (z1:zs1)]
(z1:zs1) = 1 : [i * 2 | i <- f 2]
in 1 : 2 : take 2 (x3:xs3)
==
let (x3:xs3) = [i * 2 | i <- (y2:ys2)]
(y2:ys2) = 2 : [i * 2 | i <- zs1]
zs1 = [i * 2 | i <- f 2]
in 1 : 2 : take 2 (x3:xs3)
==
let (x3:xs3) = 4 : [i * 2 | i <- ys2]
ys2 = [i * 2 | i <- zs1]
zs1 = [i * 2 | i <- f 2]
in 1 : 2 : take 2 (x3:xs3)
==
let xs3 = [i * 2 | i <- ys2]
ys2 = [i * 2 | i <- zs1]
zs1 = [i * 2 | i <- f 2]
in 1 : 2 : 4 : take 1 xs3
==
let (x4:xs4) = [i * 2 | i <- (y3:ys3)]
(y3:ys3) = [i * 2 | i <- (z2:zs2)]
(z2:zs2) = [i * 2 | i <- (w1:ws1)]
(w1:ws1) = 1 : [i * 2 | i <- f 2]
in 1 : 2 : 4 : take 1 (x4:xs4)
==
let (x4:xs4) = [i * 2 | i <- (y3:ys3)]
(y3:ys3) = [i * 2 | i <- (z2:zs2)]
(z2:zs2) = 2 : [i * 2 | i <- ws1]
ws1 = [i * 2 | i <- f 2]
in 1 : 2 : 4 : take 1 (x4:xs4)
==
let (x4:xs4) = [i * 2 | i <- (y3:ys3)]
(y3:ys3) = 4 : [i * 2 | i <- zs2]
zs2 = [i * 2 | i <- ws1]
ws1 = [i * 2 | i <- f 2]
in 1 : 2 : 4 : take 1 (x4:xs4)
==
let (x4:xs4) = 8 : [i * 2 | i <- ys3]
ys3 = [i * 2 | i <- zs2]
zs2 = [i * 2 | i <- ws1]
ws1 = [i * 2 | i <- f 2]
in 1 : 2 : 4 : take 1 (x4:xs4)
==
1 : 2 : 4 : 8 : take 0 xs4
==
1 : 2 : 4 : 8 : []
In the above derivation we used the property of list comprehensions where
[ ... | ... <- (xs ++ ys)]
===
[ ... | ... <- xs ] ++ [ ... | ... <- ys]
so that
[ ... | ... <- (x : ys)]
===
[ ... | ... <- [x] ] ++ [ ... | ... <- ys]
f a produces the same results as iterate (* a) 1, but operationally it is very much different. While the latter is linear, the former is a quadratic function, w.r.t. its time complexity.
To see what it means in practice, compare the timings for:
> f 1.01 !! 4000
1.9297236994732192e17
(1.28 secs, 1614556912 bytes)
> iterate (* 1.01) 1 !! 4000
1.9297236994732192e17
(0.00 secs, 12990984 bytes)

Related

Numbering some integer partitions

These trees represent the integer partitions of n <= 5 with at most m = 3 parts.
1 2 3 4 5
| / \ / \ |
| / \ / \ |
| / \ / \ |
1,1 2,1 2,2 3,1 3,2 4,1
| | | |
| | | |
| | | |
1,1,1 2,1,1 2,2,1 3,1,1
Let's enumerate them from top to bottom and left to right:
1 2 3 4 5
6 7 8 9 10 11
12 13 14 15
I need a list D such that D!!i is, if P is the partition numbered by i, the number of the partition P ++ [1]. That is, for this example,
D!!1 = 6, because (1,1) has number 6
D!!2 = 7 because (2,1) has number 7.
D!!3 = 9 because (3,1) has number 9.
D!!4 = 11 because (4,1) has number 11.
D!!5 = "nothing" because there's no child (5,1).
D!!6 = 12 because (1,1) has number 6 and (1,1,1) has number 12.
And so on, D!!7 = 13, D!!8 = 14, and D!!9 = 15.
I have absolutely no idea how to start. I know SO is not a code writing service but I'm asking only for any hints.
EDIT
Here is an attempt.
dico' :: Int -> Int -> Seq (Maybe Int)
dico' m n = go 1 S.empty
where
go :: Int -> Seq (Maybe Int) -> Seq (Maybe Int)
go k d'
| k == n-1 = d'
| otherwise = go (k+1) (inner 0 [0] [m] [m] 0 d')
where
inner :: Int -> [Int] -> [Int] -> [Int] -> Int -> Seq (Maybe Int) -> Seq (Maybe Int)
inner i a b c end d
| i >= length a = d -- what is the terminating condition here ?
| otherwise = if b!!i > 0
then let l = min (b!!i) (c!!i) in
let dd = d |> (Just $ end+1) in
inner (i+1) (a ++ [end + 1 .. end + l]) (b ++ map (\x -> b!!i - x) [1 .. l]) (c ++ [1 .. l]) (end + l) dd
else inner (i+1) a b c end (d |> Nothing)
It works except that the result is too long. I don't find the appropriate terminating condition of the inner loop.
> dico' 5 3
fromList [Just 1,Just 6,Just 7,Just 9,Just 11,Nothing,Just 12,Just 13,Just 14,Just 15,Nothing,Nothing,Just 16,Just 17,Nothing,Nothing,Just 18,Nothing,Nothing]
EDIT 2
Ok I get it now. I'm still interested in any improvement.
a008284_tabl :: [[Int]]
a008284_tabl = [1] : f [[1]]
where
f xss = ys : f (ys : xss)
where
ys = map sum (zipWith take [1..] xss) ++ [1]
_P :: Int -> Int -> Int
_P m n = sum (concatMap (take (min m n)) (take m a008284_tabl))
dico' :: Int -> Int -> Seq (Maybe Int)
dico' m n = go 1 S.empty
where
pmn = Just $ Just $ _P m n
go :: Int -> Seq (Maybe Int) -> Seq (Maybe Int)
go k d'
| k == n-1 = d'
| otherwise = go (k+1) (inner 0 [0] [m] [m] 0 d')
where
inner :: Int -> [Int] -> [Int] -> [Int] -> Int -> Seq (Maybe Int)
-> Seq (Maybe Int)
inner i a b c end d
| S.lookup (S.length d - 1) d == pmn = d
| otherwise = let bi = b!!i in
if bi > 0
then let l = min bi (c!!i) in
let dd = d |> (Just $ end+1) in
let range1l = [1 .. l] in
inner (i+1) (a ++ [end + 1 .. end + l])
(b ++ map (\x -> bi - x) range1l)
(c ++ range1l) (end + l) dd
else inner (i+1) a b c end (d |> Nothing)
> dico' 5 3
fromList [Just 1,Just 6,Just 7,Just 9,Just 11,Nothing,Just 12,Just 13,Just 14,Just 15]
> dico' 10 7
fromList [Just 1,Just 11,Just 12,Just 14,Just 17,Just 21,Just 26,Just 30,Just 33,Just 35,Nothing,Just 36,Just 37,Just 38,Just 40,Just 41,Just 43,Just 46,Just 47,Just 49,Just 52,Just 54,Just 55,Just 57,Just 59,Nothing,Just 60,Just 61,Just 63,Nothing,Just 64,Just 65,Nothing,Just 66,Nothing,Nothing,Just 67,Just 68,Just 69,Just 70,Just 72,Just 73,Just 74,Just 76,Just 77,Just 79,Just 80,Just 81,Just 82,Just 84,Just 85,Nothing,Just 86,Nothing,Just 87,Just 88,Just 89,Just 90,Nothing,Nothing,Just 91,Just 92,Nothing,Nothing,Just 93,Nothing,Nothing,Just 94,Just 95,Just 96,Just 97,Just 98,Just 100,Just 101,Just 102,Just 103,Just 104,Just 105,Nothing,Nothing,Just 106,Just 107,Just 108,Nothing,Just 109,Nothing,Nothing,Just 110,Just 111,Nothing,Nothing,Just 112,Nothing,Nothing,Just 113,Just 114,Just 115,Just 116,Just 117,Nothing,Just 118,Just 119,Just 120,Nothing,Just 121,Nothing,Just 122,Just 123,Nothing,Nothing,Just 124,Nothing,Nothing,Just 125,Just 126,Just 127,Just 128,Nothing,Just 129,Just 130,Nothing,Nothing,Just 131]

I/O how can i put somehing in screen withouth being string?

So im doing this function and i need her to display on the screen the result of (premio ap x) , the problem is that (premio ap x)::Maybe Int , so its not a string.
joga :: Aposta -> IO ()
joga x= do
ap <- leAposta;
let arroz = (premio ap x)
putStr ^^^^^^^^^^
return ()
How can i convert this to a string? Or there is another way to display on the screen things that are not strings.
update :full code
comuns :: Aposta -> Aposta -> (Int,Int)
comuns (Ap a (b,c)) (Ap k (l,ç)) = (cnum a k, cnum [b,c] [l,ç])
cnum::[Int]->[Int]->Int
cnum [] l2 = 0
cnum (x:xs) l2 | elem x l2 = 1 + cnum xs l2
|otherwise = cnum xs l2
premio :: Aposta -> Aposta -> Maybe Int
premio l1 l2 | x == (5,2)= Just 1
| x == (5,1)= Just 2
| x == (5,0)= Just 3
| x == (4,2)= Just 4
| x == (4,1)= Just 5
| x == (4,0)= Just 6
| x == (3,2)= Just 7
| x == (2,2)= Just 8
| x == (3,1)= Just 9
| x == (3,0)= Just 10
| x == (1,2)= Just 11
| x == (2,1)= Just 12
| x == (2,0)= Just 13
|otherwise = Nothing
where
x = comuns l1 l2
leAposta :: IO Aposta
leAposta = do
putStrLn "Insira como lista as 5 estrelas"
num <-getLine
putStrLn "Insira em par as 2 estrelas"
es<-getLine
let ap = (Ap (read num) (read es))
if (valida ap)
then return ap
else do
putStrLn "Aposta invalida"
leAposta
Since arroz is premio ap x which has type Maybe Int, you can simply print arroz.
print works on any type that can be printed, i.e. on those types in class Show.
(You probably don't want to use print on values that are already strings, though, since that will print the escaped string, with quotes around. Use putStr and putStrLn for strings.)

Pretty Printing list of lists

I have a list of lists:
[[5,1,0,0,5,5,0,0],[0,0,1,4,2,0,6,1],[1,1,6,3,0,1,0,0],[1,5,0,0,0,1,1,6]]
and a string "wxyz"
I would like to have:
1)
w: 5 1 0 0 5 5 0 0
x: 0 0 1 4 2 0 6 1
y: 1 1 6 3 0 1 0 0
z: 1 5 0 0 0 1 1 6
I wrote:
f c xs = putStrLn (c : ':' : ' ' : concat (intersperse " " $ map show xs))
to write one line
and 2)
g xxs c = mapM_ (f c) xxs
How can I modify 2) to loop through string "wxyz" in order to have 1) ?
Instead of mapM_, you can use zipWithM_ from Control.Monad:
g xss cs = zipWithM_ f cs xss
or, if you change the order of arguments in either f or g to match, you can do it with less "points":
g = zipWithM_ f
Also, concat (intersperse " " ...) is otherwise known as unwords ....
You can use zip and uncurry:
g xxs c = mapM_ (uncurry f) (zip xxs c)

haskell error parse error (possibly incorrect indentation)

this is my code
font a = let x= ord a in
if x>=0 || x<=31 || x>=126 then ["*****","*****","*****","*****","*****","*****","*****"]
else
auxfont (fontBitmap!!(x-32))
where
auxfont b = let y = map trns (map rInt (map show b)) in
convertir y []
trns z = modA [] 1 z
modA o l k
| l < 8 = modA (o++[(k `mod` 2)]) (l+1) (k `div` 2)
| otherwise o
convertir (e1:e2:e3:e4:e5) f
| e1==[] = f
| otherwise convertir [tail(e1),tail(e2),tail(e3),tail(e4),tail(e5)] (f++[(psr(head(e1)))++(psr(head(e2)))++(psr(head(e3)))++(psr(head(e4)))++(psr(head(e5)))])
psr 0 = " "
psr 1 = "*"
and i had and this error in convertir:
[1 of 2] Compiling Pixels ( Pixels.hs, interpreted )
Pixels.hs:122:13: parse error (possibly incorrect indentation)
Failed, modules loaded: none.
Why the error
Every (normal) guard is of the form
| boolean expression = value
You missed this out for your otherwise cases. It works like this because otherwise is defined as
otherwise = True
so it's not a keyword like else, it's just a human-readable "always", and since the guards are tried top-to-bottom, this is a catch-all for anything that wasn't true above.
Some corrections
font a = let x= ord a in
if x>=0 || x<=31 || x>=126 then ["*****","*****","*****","*****","*****","*****","*****"]
else
auxfont (fontBitmap!!(x-32))
where
auxfont b = let y = map trns (map rInt (map show b)) in
convertir y []
trns z = modA [] 1 z
modA o l k
| l < 8 = modA (o++[(k `mod` 2)]) (l+1) (k `div` 2)
here:
| otherwise = o -- added =
convertir (e1:e2:e3:e4:e5) f
| e1==[] = f
and here:
| otherwise = convertir [tail(e1),tail(e2),tail(e3),tail(e4),tail(e5)] (f++[(psr(head(e1)))++(psr(head(e2)))++(psr(head(e3)))++(psr(head(e4)))++(psr(head(e5)))])
psr 0 = " "
psr 1 = "*"
Some abbreviations
By the way,
["*****","*****","*****","*****","*****","*****","*****"] is replicate 7 "*****" and
map trns (map rInt (map show b)) is map (trns.fInt.show) b.
Also [tail(e1),tail(e2),tail(e3),tail(e4)] is map tail [e1,e2,e3,e4,e5]
but I think you have a type error with :e5, because it has to be a list of lists in the pattern (e1:e2:e3:e4:e5) but you've used it like an element tail(e5).
Also [(psr(head(e1)))++(psr(head(e2)))++(psr(head(e3)))++(psr(head(e4)))++(psr(head(e5)))] is map (psr.head) [e1,e2,e3,e4,e5].

FizzBuzz cleanup

I'm still learning Haskell, and I was wondering if there is a less verbose way to express the below statement using 1 line of code:
map (\x -> (x, (if mod x 3 == 0 then "fizz" else "") ++
if mod x 5 == 0 then "buzz" else "")) [1..100]
Produces:
[(1,""),(2,""),(3,"fizz"),(4,""),(5,"buzz"),(6,"fizz"),(7,""),(8,""),(9,"fizz"),(10,"buzz"),(11,""),(12,"fizz"),(13,""),(14,""),(15,"fizzbuzz"),(16,""),(17,""),(18,"fizz"),(19,""),(20,"buzz"),(21,"fizz"),(22,""),(23,""),(24,"fizz"),(25,"buzz"),(26,""),(27,"fizz"),(28,""),(29,""),(30,"fizzbuzz"), etc
It just feels like I'm fighting the syntax more than I should. I've seen other questions for this in Haskell, but I'm looking for the most optimal way to express this in a single statement (trying to understand how to work the syntax better).
We need no stinkin' mod...
zip [1..100] $ zipWith (++) (cycle ["","","fizz"]) (cycle ["","","","","buzz"])
or slightly shorter
import Data.Function(on)
zip [1..100] $ (zipWith (++) `on` cycle) ["","","fizz"] ["","","","","buzz"]
Or the brute force way:
zip [1..100] $ cycle ["","","fizz","","buzz","fizz","","","fizz","buzz","","fizz","","","fizzbuzz"]
If you insist on a one-liner:
[(x, concat $ ["fizz" | mod x 3 == 0] ++ ["buzz" | mod x 5 == 0]) | x <- [1..100]]
How's about...
fizzBuzz = [(x, fizz x ++ buzz x) | x <- [1..100]]
where fizz n | n `mod` 3 == 0 = "fizz"
| otherwise = ""
buzz n | n `mod` 5 == 0 = "buzz"
| otherwise = ""
Couldn't resist going in the other direction and making it more complicated. Look, no mod...
merge as#(a#(ia,sa):as') bs#(b#(ib,sb):bs') =
case compare ia ib of
LT -> a : merge as' bs
GT -> b : merge as bs'
EQ -> (ia, sa++sb) : merge as' bs'
merge as bs = as ++ bs
zz (n,s) = [(i, s) | i <- [n,2*n..]]
fizzBuzz = foldr merge [] $ map zz [(1,""), (3,"fizz"), (5,"buzz")]
Along the same lines as larsmans' answer:
fizzBuzz = [(x, f 3 "fizz" x ++ f 5 "buzz" x) | x <- [1..100]]
where f k s n | n `mod` k == 0 = s
| otherwise = ""
I think the reason why you feel like you are fighting the syntax is because you are mixing too many types.
Instead of trying to print:
[(1, ""), (2,""), (3,"Fizz")...]
Just think of printing strings:
["1","2","Fizz"...]
My attempt:
Prelude> let fizzBuzz x | x `mod` 15 == 0 = "FizzBuzz" | x `mod` 5 == 0 = "Buzz" | x `mod` 3 == 0 = "Fizz" | otherwise = show x
Prelude> [fizzBuzz x | x <-[1..100]]
["1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11","Fizz","13","14","FizzBuzz"...]
In order to convert an Int to String you use the:
show x
Just for studying
zipWith (\a b -> b a) (map show [1..100]) $ cycle [id,id,const "fizz",id,const "buzz",const "fizz",id,id,const "fizz",const "buzz",id,const "fizz",id,id,const "fizzbuzz"]
produces
["1","2","fizz","4","buzz","fizz","7","8","fizz","buzz","11","fizz","13","14","fizzbuzz","16","17","fizz","19","buzz","fizz","22","23","fizz","buzz","26","fizz","28","29","fizzbuzz","31","32","fizz","34","buzz","fizz","37","38","fizz","buzz","41","fizz","43","44","fizzbuzz","46","47","fizz","49","buzz","fizz","52","53","fizz","buzz","56","fizz","58","59","fizzbuzz","61","62","fizz","64","buzz","fizz","67","68","fizz","buzz","71","fizz","73","74","fizzbuzz","76","77","fizz","79","buzz","fizz","82","83","fizz","buzz","86","fizz","88","89","fizzbuzz","91","92","fizz","94","buzz","fizz","97","98","fizz","buzz"]
Writer monad may look nice (if you don't like concat):
fizzBuzz = [(x, execWriter $ when (x `mod` 3 == 0) (tell "fizz") >> when (x `mod` 5 == 0) (tell "buzz")) | x <- [1..100]]
It's not particularly succinct though.

Resources