Use 'let' in 'if' expression - haskell

I need a function that works like this:
foo :: Integer -> Integer -> [Integer]
foo a b = do
let result = []
let Coord x y = boo a b
if x > 0
let result = result ++ [3]
if y > 0
let result = result ++ [5]
if x < a
let result = result ++ [7]
if y < b
let result = result ++ [9]
result
I can not use the guards because the result can have more then one element. But as I see I can not use 'let' in the 'if' expression:
all_possible_combinations.hs:41:14: parse error on input `let'
How can I check multiple expressions and add new elements in the list?
I search not only imperative solution, but the functional one.

Other people have said why what you tried doesn't work. Here is a concise way of doing what you want:
foo :: Integer -> Integer -> [Integer]
foo a b = map snd (filter fst [(x > 0, 3),
(y > 0, 5),
(x < a, 7),
(y < a, 9)])
where Coord x y = boo a b
So how does this work?
We start with a list of pairs. The second element of each pair is the value we might want to include in the return value from foo. The first element of each pair tells us whether we actually want to include it.
Then we call filter fst, which throws away all the pairs where the condition is false.
Finally, we call map snd, which throws away the conditions (all the ones that are left are true), and keeps the values we are interested in.

Three things:
You can use let inside an if expression, but it needs to be followed by in or inside a do block. Either way the expression which uses the name you just bound with let, needs to be in the same if. I.e. you can do:
if x > 0
then let a = 42 in a+x
else 23
but not
if x > 0
then let a = 42 in ()
else let a = 23 in ()
print a
You can not use let to change the value of an existing variable. As a matter of fact, you can not change the value of a variable, ever.
If you use the name bound on the LHS of = on the RHS of the = it will refer recursively to itself - not to any previous binding. In other words let x = x+1, causes infinite recursion, it does not increase the value of x by one.
To do what you want to, you'd need to restructure your code to something like this:
let result1 = if x > 0 then [3] else []
let result2 = if y > 0 then result1 ++ [5] else result1
let result3 = if x < a then result2 ++ [7] else result2
if y < b then result3 ++ [9] else result3
Note that it's usually a bad idea, performance wise, to use ++ to append at the end, instead of using : and then reverseing the list at the end.

EDIT: My thanks to sepp2k for pointing out what was intended. It was even more imperative than I could grok with my Haskell-colored glasses on...
Here's a quick-n-dirty solution:
result = (if x > 0 then [3] else []) ++
(if y > 0 then [5] else []) ++
(if x < a then [7] else []) ++
(if y < b then [9] else [])
(Old answer deleted.)

You have also an issue in the way you think if should be used. In Haskell if is an expression, i.e. it evaluates to a value. Because of this, it must always be accompanied by an else branch. Marcelo's example should clarify this. If you want something like the if statement in an imperative language, then you have Control.Monad.when or Control.Monad.unless.

There are a number of things wrong with your code, unfortunately. The first problem is the do on the top line: you aren't using any monads, so you shouldn't have it at all. The rest of the code is trying to work in an imperative manner, but this (unsurprisingly) doesn't work in Haskell. In Haskell, every expression needs to have a result; for this reason, all if statements must be of the form if ... then ... else .... Similarly, every let binding must be of the form let ... in ...; it's impossible to change the value of a variable, so if you left off the in, nothing would happen. And because of this, each line let result = result ++ [3], if it could be executed, would try to make a list result which consisted of all of its elements with a three at the end—in other words, a self-referential list! (The canonical example of such a thing is let ones = 1:ones in ones to create a list whose tail is itself and thus contains only 1s.)
So now the question is, what does your function want to do? You have four boolean conditions, and want to add a different element to your list for each one. There are a number of ways you could write this instead. One approach is
foo :: Integer -> Integer -> Integer
foo a b = let Coord x y = boo a b
checkAdd cond elem = if cond then (elem :) else id
in foldr (uncurry checkAdd) []
[(x > 0, 3), (y > 0, 5), (x > a, 7), (y > b, 9)]
First, we call boo and look at the results. We then define a checkAdd function, which has type checkAdd :: Bool -> a -> ([a] -> [a]). If its first argument is true, then it returns a function which prepends its second argument to a list; otherwise, it returns a function which does nothing to a list. So checkAdd True 1 x == 1:x, and checkAdd False 1 x == x. The last line is admittedly a little mysterious, but it's not too bad. If you have a list fns = [f1,f2,...,fn] of functions, and want to produce f1(f2(...(fn(x))...)), then you can use foldr ($) x fns. This fold is similar, except we have uncurry checkAdd instead of $; uncurry causes a function to take a tuple instead of two arguments, and so when we foldr it over the list, checkAdd produces a function for each element. Then, each function is applied, and you arrive at the list you wanted. The reason we don't have ($) . uncurry checkAdd is that $ is really just the identity function with low precedence; this makes sense, since $'s only purpose is to have really low precedence but not do anything.
Of course, this code looks completely different from what you had above, but that's part of what's interesting about trying out completely different languages :-)

This sort of append-output is very natural with the Writer monad.
import Control.Monad.Writer
foo a b = execWriter $ do
let Coord x y = boo a b
when (x > 0) $ tell [3]
when (y > 0) $ tell [5]
when (x < a) $ tell [7]
when (x < b) $ tell [9]

As already mentioned you are looking at this the wrong way. You can't change the value of an variable in Haskell, and if-then-else expressions always have an else clause. I have made some code that looks and feels like what you were trying to do, but as you have seen, there are many better ways of doing this.
foo a b = let Coord x y = boo a b in
(if x > 0 then (3 :) else id) .
(if y > 0 then (5 :) else id) .
(if x < a then (7 :) else id) .
(if x < b then (9 :) else id) $
[]

Related

Square of even numbers in Haskell

I am trying to write a basic function in Haskell as shown below. My aim is provide the code to square only even numbers while odd numbers will stay same. Would you please help me regarding this issue.
square:: Int -> Int
square x = [ x*x | x <- [1..10], mod x 2 == 0 ]
regards
You are here filtering. You should determine if the number is even or odd and then square the number or not, this can be done in the yield part of the list comprehension.
But the type signature hints that you do not need to construct a list at all. You simply check if the parameter x is even, and if that is the case return x*x, otherwise return x:
square:: Int -> Int
square x = if even x then x*x else x
or through guards:
square:: Int -> Int
square x
| even x = x*x
| otherwise = x
One quite straightforward answer to your question is, you can inline a if statment directly into your list comprehension like so:
[ if even x then x * x else x | x <- [1..10] ]
This is possible since if is an expression in Haskell, meaning it evaluates to a value, so things like this are valid:
let _ = if 1 + 1 == 2 then "foo" else "bar"
It can also be good to look at this problem in another direction. List comprehensions can be quite nice, but sticking an if within it can get pretty messy. Willem's solution of factoring out the method is great, so let's look at other ways we can leverage it with your code:
-- This is the function we're trying to implement
evenSquares :: [Int] -> [Int]
-- We could start by noting that `if` expression has a nice name,
-- which can be factored out to make things look cleaner
-- Same implementation as Willem's
evenSquares xs = [ squareIfEven x | x <- xs ] where
squareIfEven x = if even x then x * x else x
-- List comprehensions are nice, but there's also another name for what we're doing,
-- which is mapping over a collection of values and applying a method
evenSquares xs = map squareIfEven xs where
squareIfEven x = if even x then x * x else x
-- Note how the `xs` is an argument to `evenSquares` and also the last argument to `map`
-- We can actually get rid of `xs` entirely via this rule:
-- https://wiki.haskell.org/Eta_conversion
evenSquares = map squareIfeven where
squareIfEven x = if even x then x * x else x
-- This one's a bit of a stretch, but conceptually quite useful
-- The idea of 'apply a method if a condition is true' can be expressed as a method
-- which takes a predicate method, a transformation method, and a value
-- We can leverage this ourselves to make `squareIfEven` more generic too
evenSquares = map (if' even square id) where
square x = x * x
if' pred fst snd x = if pred x then fst x else snd x
-- There's a bunch more solutions we can try, including things like `do` notation
-- This is just an idea of how you could look at your problem
-- Pick one which makes your solution clear and concise!

Haskell find divisors based on comprehension method

I need a little help understanding a comprehension method function.
compdivides :: Integer -> [Integer]
compdivides x
| x > 0 = [a | a <-[1..div x 2], mod x a == 0] ++ [x]
| otherwise = compdivides (abs x)
I understand that if x is positive we do the 3rd line otherwise the 4th line.
In the third line we check whether mod x a == 0 only then do we do everything else.
However, I cannot seem to understand this part a <-[1..div x 2] What exactly happens here?
Also, why do we do this at the end ++ [x] ? What exactly are we doing here anyways?
itemTotal :: [(String, Float)] -> [(String, Float)]
itemTotal [] = []
itemTotal [x] = [x]
I am having some trouble with this as well.
I understand that if the list is empty we simply return an empty list.
However, what are we saying here? itemTotal [x] = [x] That if the list only has one thing we simply return that one thing?
Thank you so much for the help!
However, I cannot seem to understand this part a <-[1..div x 2] What exactly happens here?
This is a generator of the list comprehension. The list comprehension:
[ a | a <- [1 .. div x 2 ], mod x a == 0 ]
will evaluate such that a takes each item in the list (so 1, 2, …, x/2), and in case mod x a == 0 (x is dividable by a), it will add a to the list.
Also, why do we do this at the end ++ [x] ? What exactly are we doing here anyways?
It appends x at the end of the list. This is done because a number x is always dividable by itself (x), since the a <- [1 .. div x 2] stops at div x 2, it will never check if x divides x.
The function will get stuck in an infinite loop for compdivides 0, so you might want to rewrite the function to cover this case as well.
However, what are we saying here? itemTotal [x] = [x] That if the list only has one thing we simply return that one thing?
Yes. Usually a pattern like itemTotal (x : xs) = x : itemTotal xs is used where we thus return a list where x is the first item, and we recurse on the tail of the list xs.
Your itemTotal function however only makes a copy of the list for the first two clauses. You thus can simply define itemTotal = id. Likely you will need to rewrite the function to determine the total of the items in the list.

Clean syntax for conditionally folding a list in Haskell

I'm relatively new to haskell, but in my searching I couldn't find an easy way to conditionally fold a list. i.e. When an element satisfies a condition (like in filter) to fold that element by a function (like foldr and foldl).
My workaround was to write the following helper function, then apply map to change the resulting list of pairs as my situation required.
-- This function returns tuples containing the elements which
-- satisfy `cond` folded right, adding 1 to the second value
-- in each pair. (`snd` pair starts at 0)
-- Condition takes a single value (similar to `filter`)
-- NOTE: list cannot end with token
foldrOn cond list =
if (length list) > 0 then
if cond (head list) then
do
let tmp = foldrOn cond (tail list)
(fst (head tmp), snd (head tmp) + 1) : (tail tmp)
-- fold token into char after it
else
(head list, 0) : (foldrOn cond (tail list))
-- don't fold token
else
[] -- base case len list = 0
foldlOn cond list = ...
For example, the use-case would be something along the lines of wanting to remove the zeros in the following lists but remember how many were removed between each value.
-- the second value in each resultant pair represents the number of
-- zeroes preceding the corresponding first value in the original list.
foldrOn (== 0) [1,0,0,0,0,0,1,0,0,0,1] -- [(1,0),(1,5),(1,3)]
foldrOn (== 0) [1,0,0,12,0,13] -- [(1,0),(12,2),(13,1)]
Is there a better way to accomplish this?
Additionally, can this be done more optimally?
First of all,
foldrOn :: Num t => (a -> Bool) -> [a] -> [(a, t)]
-- foldrOn (== 0) [1,0,0,0,0,0,1,0,0,0,1] -- [(1,0),(1,5),(1,3)]
foldrOn p xs = foldr g [] xs
where
g x [] = [(x,0)]
g x ((y,n):r)
| p x = ((y,n+1):r)
g x r = ((x,0):r)
This is the simplest, though it is recursive, i.e. will force the whole list to the end before starting returning its result.
To make it maximally lazy we'd have to use a lazy left fold. The skipping over the p-satisfying elements is still a recursive step, but at least the process will pause between each such span.
Lazy left fold is usually implemented as a foldr with additional argument being passed left to right along the list:
foldlOn :: Num t => (a -> Bool) -> [a] -> [(a, t)]
-- foldlOn (== 0) [1,0,0,0,0,0,1,0,0,0,1] -- [(1,0),(1,5),(1,3)]
foldlOn p xs = foldr g z xs 0
where
g x r i | p x = r (i+1)
| otherwise = (x,i) : r 0
z _i = []
Or you could combine span/break and unfoldr to do the same.
You might find a way to use groupBy with some post-processing step:
GHCi> groupBy (\a b -> (==0) b) [1,0,0,0,0,0,1,0,0,0,1]
[[1,0,0,0,0,0],[1,0,0,0],[1]]
GHCi> groupBy (const (==0)) [1,2,0,0,1,0,1]
[[1],[2,0,0],[1,0],[1]]
Finishing this should not be a problem.
You can always bring some builtin machinery. The Data.List library is quite powerful:
import Data.List(mapAccumL)
import Data.Maybe(catMaybes)
foldrOn cond = catMaybes . snd . mapAccumL combine 0 where
combine a el =
if cond el then (a + 1, Nothing)
else (0, Just (el, a))
What's going on
Essentially, foldrOn cond is a composition of the following functions:
mapAccumL combine 0 which advances along the list modifying each element by information about the number of recently skipped entities (starting the count at 0 and resetting it whenever we find something that doesn't match the cond predicate).
snd which discards the final state from the mapAccumL's result
catMaybes which removes the Maybe layer and leaves only the "present" values.
Let's start by using pattern matching to make your own implementation more idiomatic, more obviously correct, and also (much) faster. We can also use guards in an idiomatic fashion rather than if/then/else; this is rather less important. There's also no reason to use do here, so we won't.
foldrOn _cond [] = []
foldrOn cond (hd : tl)
| cond hd
= case foldrOn cond tl of
(x, y) : tl' -> (x, y + 1) : tl'
-- fold token into char after it
[] -> error "String ended on token."
| otherwise
= (hd, 0) : foldrOn cond tl
-- don't fold token
This is ... okay. But as Will Ness suggests, we don't actually gain anything by consing an "incomplete" element onto the result list. We can instead count up the cond-satisfying tokens until we reach the end of the block, and then produce a complete element. I think this makes the code a little easier to understand, and it should also run a little bit faster.
foldrOn cond = go 0
where
go count (hd : tl)
| cond hd
= go (count + 1) tl -- Don't produce anything; just bump the count
| otherwise
= (hd, count) : go 0 tl -- Produce the element and the count; reset the count to 0
go count []
| count == 0
= []
| otherwise
= error "List ended on a token."
To actually run faster, you might need to tell the compiler explicitly that you really want to calculate the counts. You probably don't need to understand this part just yet, but it looks like this:
-- At the top of the file, add this line:
{-# LANGUAGE BangPatterns #-}
foldrOn cond = go 0
where
go !count (hd : tl)
| cond hd
= go (count + 1) tl -- Don't produce anything; just bump the count
| otherwise
= (hd, count) : go 0 tl -- Produce the element and the count; reset the count to 0
go count []
| count == 0
= []
| otherwise
= error "List ended on a token."
This can be written as a fold in the manner Will Ness demonstrates.
Note: while it's possible to avoid the BangPatterns language extension, doing so is a bit annoying.

What is a = a doing in haskell? [duplicate]

I was learning some new Haskell today, when I tried something in ghci.
It basically boiled down to this:
Prelude> let x = 6
Prelude> x
6
Prelude> let y = show x
Prelude> y
"6"
Prelude> let x = show x
Prelude> x
"\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" --(repeats)
So can ghci not self-reference in assignment? I feel like it's akin to i = i++; in C, or trying to reference previous assignments of a let (not let*) in Scheme. Is there anyway to do this, or should I just use the easier let y = show x?
Definitions in Haskell are recursive by default. So the definition you made for x refers to the very same x, which is the reason for the very long string you are seeing, because x is defined to a String that is the result of calling show on itself, so you keep seeing the opening quotes for showing a string, and then those opening quotes escaped, and so on.
These kinds of definitions can be surprisingly useful. For example if you write:
let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
you can define the Fibonacci sequence in terms of itself as an infinite list.
Then you can do something like take 10 fibs to just see the first 10 elements.
It's self referencing indeed! It's trying to solve the equation
x = show x
Since show returns a string Haskell knows that x begins like "\"" and that's enough to guess the second character, which is enough for the third which is enough for the fourth...
And so on.
Yes, you can do a not-selfreferencing assignment in ghci, although it's a bit cumbersome:
let x = 5
x <- return $ show x
lets are recursive, while monadic bindings are not.
Again: yes, Haskell very much can self-reference in assignment, otherwise this would just give an error instead of printing something undecipherable, wouldn't it?
What you can not do in Haskell, ever, is modify / re-assign the value of a variable. It's just totally out of question: if you've once defined x as some value, x will keep this value forever. An assumption baked into the very language, and used to great avail by the compiler for lots of optimisations etc..
Now you wonder why you can write let x = ... again at all, didn't I just say this is not possible? The thing is, what you're doing there is define a new variable that also happens to have the name x, but that doesn't change anything about the old variable with the same name. You might expect this
Prelude> let x = 6
Prelude> let p = print x
Prelude> let x = 7
Prelude> p
to yield 7, but actually it prints 6 because p is still referring to the old variable x, not to the new one that was defined only later.
Still confused? Perhaps less strange is something like
n :: Int
n = 7
f :: IO ()
f = print $ replicate n "ha"
... -- much later, you've forgotten there was a global `n` up there...
g :: String -> String
g = take n
where n = 37
It's quite reasonable that f will take 37 characters, not 7, while any call to f continues to repeat the string only 7 times. After all, it's "g, where n has that value", but nothing else outside. Now, let is just where written the other way around. In particular, a do notation or your GHCi prompt is actually syntactic sugar for something like this:
let x = 6
in ( print x >> ( let y = show x
in ( print y >> ( let x = show x
in ( print x )
)
)
)
Each paren encloses a scope. Variables defined in outer scopes can be used, but local ones are preferred if found. So let x = show x in ( print x ) can be considered completely on its own, the original x = 6 is shadowed out of scope here. Therefore, the only way the definition can work is refer recursively to itself.

ghci self-referencing assignment

I was learning some new Haskell today, when I tried something in ghci.
It basically boiled down to this:
Prelude> let x = 6
Prelude> x
6
Prelude> let y = show x
Prelude> y
"6"
Prelude> let x = show x
Prelude> x
"\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" --(repeats)
So can ghci not self-reference in assignment? I feel like it's akin to i = i++; in C, or trying to reference previous assignments of a let (not let*) in Scheme. Is there anyway to do this, or should I just use the easier let y = show x?
Definitions in Haskell are recursive by default. So the definition you made for x refers to the very same x, which is the reason for the very long string you are seeing, because x is defined to a String that is the result of calling show on itself, so you keep seeing the opening quotes for showing a string, and then those opening quotes escaped, and so on.
These kinds of definitions can be surprisingly useful. For example if you write:
let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
you can define the Fibonacci sequence in terms of itself as an infinite list.
Then you can do something like take 10 fibs to just see the first 10 elements.
It's self referencing indeed! It's trying to solve the equation
x = show x
Since show returns a string Haskell knows that x begins like "\"" and that's enough to guess the second character, which is enough for the third which is enough for the fourth...
And so on.
Yes, you can do a not-selfreferencing assignment in ghci, although it's a bit cumbersome:
let x = 5
x <- return $ show x
lets are recursive, while monadic bindings are not.
Again: yes, Haskell very much can self-reference in assignment, otherwise this would just give an error instead of printing something undecipherable, wouldn't it?
What you can not do in Haskell, ever, is modify / re-assign the value of a variable. It's just totally out of question: if you've once defined x as some value, x will keep this value forever. An assumption baked into the very language, and used to great avail by the compiler for lots of optimisations etc..
Now you wonder why you can write let x = ... again at all, didn't I just say this is not possible? The thing is, what you're doing there is define a new variable that also happens to have the name x, but that doesn't change anything about the old variable with the same name. You might expect this
Prelude> let x = 6
Prelude> let p = print x
Prelude> let x = 7
Prelude> p
to yield 7, but actually it prints 6 because p is still referring to the old variable x, not to the new one that was defined only later.
Still confused? Perhaps less strange is something like
n :: Int
n = 7
f :: IO ()
f = print $ replicate n "ha"
... -- much later, you've forgotten there was a global `n` up there...
g :: String -> String
g = take n
where n = 37
It's quite reasonable that f will take 37 characters, not 7, while any call to f continues to repeat the string only 7 times. After all, it's "g, where n has that value", but nothing else outside. Now, let is just where written the other way around. In particular, a do notation or your GHCi prompt is actually syntactic sugar for something like this:
let x = 6
in ( print x >> ( let y = show x
in ( print y >> ( let x = show x
in ( print x )
)
)
)
Each paren encloses a scope. Variables defined in outer scopes can be used, but local ones are preferred if found. So let x = show x in ( print x ) can be considered completely on its own, the original x = 6 is shadowed out of scope here. Therefore, the only way the definition can work is refer recursively to itself.

Resources