how to have multiple if statements in Haskell? - if-statement

like consider the following python code,
n = 4
if n>3 :
n = 5
if n>2 :
n = 6
if n>1 :
n = 4
How to achieve this in haskell??
let n = 4
main :: IO()
main = do
if n>3 then let n = 5
if n>2 then let n = 6
if n>1 then let n = 4
Tried this but gives an error, looking for some modifications

As I commented there are some points of your program you should checkout
else must be used after if
You don't use let for top level declarations (as in let n = 4).
When you write if n>3 then let n=5 you are not changing the value of n because values are inmutables in Haskell
There are a few "idiomatic" ways you can rewrite your program
Use a chained if then else with prints. This is the closest to your code
n = 4 -- no let in top level binding
main :: IO()
main = do
if n>3 then print 5 -- do not use let n=5 because n can't be mutated
else if n>2 then print 6
else if n>1 then print 4
else print ()
Use an external function and guards. This is the most idiomatic
f :: Int -> Int
f x | x > 3 = 5
| x > 2 = 6
| x > 1 = 4
n = 4
main = do
print (f n)
As #davidflecher commented, you can use guards within a let binding
n = 4
main :: IO()
main = do
let x | n > 3 = 5
| n > 2 = 6
| n > 1 = 4
print x
Use MultyWayIf extension (This is more advance as it needs extensions to the language)
{-# LANGUAGE MultiWayIf #-}
n = 4
main :: IO()
main = do
let x = if | n > 3 -> 5
| n > 2 -> 6
| n > 1 -> 4
print x

While the example is a bit contrived, the usual way to encode an if with multiple branches is to use a case-of with () as the scrutinee as follows:
main :: IO()
main = do
case () of
_ | n > 3 -> ...
| n > 2 -> ...
| otherwise -> ...
or when part of a binding, by use of a guarded let
let x | n > 3 = ...
| n > 2 = ...
| otherwise = ...
Alternatively, this may also be encoded as guards of a helper function
f :: Int -> Int
f n | n > 3 = 5
| n > 2 = 6
| otherwise = 4
Updated to include #Iceland_jack's comment

Related

Generating Simple List from 1 to 10 with haskell

I am new in Haskell, could guys help me how to generating list from 1 to 10.
I tried to make like this:
seqList :: Integer -> [Integer]
seqList 1 = [1]
seqList n = n : seqList(n-1)
The result 10 to 1, not 1 to 10
And second question
can we make function as value.
numList :: [Integer]
numList = [1,2..10]
totJum :: Int
totJum = length numList
takeNum :: Int->[Integer]
takeNum totJum
| totJum >= 10 = take 5 numList
| totJum == 10 = numList
With this code, i want to call output if the length from numlist matches the condition.
For the first one you can work with an accumulator: a variable you use to yield a value and each time increment in the recursive call, so:
seqList :: Integer -> [Integer]
seqList n = go 1
where go i
| i <= … = …
| otherwise = …
where I leave filling in the … parts as an exercise.
with this code, I want to call output if the length from numlist matches the condition.
You should not use totJum as a parameter, but just use it in the body of the function, so:
takeNum :: [Integer]
takeNum
| totJum >= 10 = take 5 numList
| totJum == 10 = numList
Note however that here you do not cover the case where totJum is less than or 10. In that case the function will thus error. You thus might want to add an otherwise clause.

Adding 0-s to a list of until it's length is 8 in Haskell

So I have to make a decimal number into binary list like so: intToBitString 4 = [1,0,0].
Which i have done like so:
intToBitString n = reverse (helper n)
helper 0 = []
helper n
| n `mod` 2 == 1 = 1 : helper (n `div` 2)
| n `mod` 2 == 0 = 0 : helper(n `div` 2)
But then I also have to make a function called intToByte, which pads out the list with 0-s until it's length is 8 elements long. (so making it a bytestring) Like this:
intToByte 7 = [0, 0, 0, 0, 0, 1, 1, 1]
I have tried so many things, but they never work. I am a beginner, so I only know the "if" loop the way I showed above, and recursion, but I dont know anything fancy. One of my tries:
intToByte 0 = [0]
intToByte n
| eight n == helper2 n = reverse (helper2 n)
| otherwise = eight n
helper2 0 = []
helper2 n
| n `mod` 2 == 1 = 1 : helper2 (n `div` 2)
| n `mod` 2 == 0 = 0 : helper2 (n `div` 2)
eight n
| length (helper2 n) < 8 = 0 : eight n
| otherwise = helper2 n
I have been working on this for so many hours that i'm getting confused by it. But this is part of an important assignment, so help would be very appreciated!
First of all, you can simplify your code with:
helper2 :: Integral i => i -> [i]
helper2 0 = []
helper2 n = r : helper2 q
where (q,r) = quotRem n 2
Secondly, the above is a big endian representation [wiki]. Indeed, 7 is represented as [1,1,1], whereas 14 is for example represented as [0,1,1,1]. If we want to revers this, we can work with an accumulator:
helper2 :: Integral i => i -> [i]
helper2 = go []
where go rs 0 = rs
go rs n = go (r:rs) q
where (q,r) = quotRem n 2
This thus maps 7 to [1,1,1] and 14 to [1,1,1,0]. But now we still need to add leading zeros. We can do that for example by maintaing the number of elements already added to the list:
eight :: Integral i => i -> [i]
eight = go [] 0
where go rs l 0 = replicate (8-l) 0 ++ rs
go rs l n = go (r:rs) (l+1) q
where (q,r) = quotRem n 2
Padding can be as simple as computing how many additional elements to push to the list and then have those elements produced using the function replicate from the Prelude:
padLeft :: Int -> a -> [a] -> [a]
padLeft n x xs = replicate (n - length xs) x ++ xs
For instance:
> padLeft 8 0 [1, 1, 0]
[0,0,0,0,0,1,1,0]
One approach would be to define a function bits such that bits k converts its argument to a bit string of length k:
bits :: Int -> Int -> [Int]
bits 0 _n = []
bits k n | n < 0 = error "bits: negative"
| n > 2 * m - 1 = error "bits: overflow"
| otherwise = let (i, j) = n `divMod` m in i : bits (k - 1) j
where m = 2 ^ (k - 1)
Your function eight is then easily written as
eight :: Int -> [Int]
eight = bits 8
This gives:
> eight 4
[0,0,0,0,0,1,0,0]
> eight 7
[0,0,0,0,0,1,1,1]

Find the product of the digits of a number

I have to write a recursive function the calculates the product of the digits of a number. What I wrote down is:
let rec digits_product x = if x = 0 then 0 else let n = x mod 10 in n * digits_product (x/10)
The problem is that it always returns me 0. I am sure there is something I miss out but I can not find out. Can you help me solve the problem? The code should calculate the product of the digits of a number, for example if I enter 12345 it should return 12345 which is equal to 120.
UPDATE
I changed the code to this:
let rec digits_product x = match x with | 0 -> 0
| 1 -> 1
| 2 -> 2
| 3 -> 3
| 4 -> 4
| 5 -> 5
| 6 -> 6
| 7 -> 7
| 8 -> 8
| 9 -> 9
| _ -> (x mod 10) * digits_product (x/10)
It works right now, but I have another question: is there a more efficient way to do it?
Your code always makes a recursive call unless the parameter x is 0. Since it doesn't show signs of infinite recursion, you know that it is returning 0 at least once. This should be enough to show what is wrong.
Update
You are checking the input for 0 because the answer is obvious in that case. But there are other inputs where the answer is obvious. I.e., where you don't need to do any multiplications to get the result. Why not check for all of these? You can check for all of these values with just one test.
IMO, the syntax would look cleaner like so:
let rec produsul_cifrelor x =
match x with
| n when n < 10 -> n
| _ -> (x mod 10) * produsul_cifrelor (x/10)
Then running produsul_cifrelor 12345 will return 120.

Build a sequence from a function

I wrote these function to build a sequence from a function i am having a stack overflow error while testing it
let rec from_fun f ()=
match f () with
| None -> Nil
| Some e -> Cons(e, from_fun f)
from_fun (fun () -> let x = 0 in if x<10 then Some (x+1) else None)
thanks
Your function always returns Some 1. It never returns None. So the sequence is infinitely long and the stack overflows while building it.
If you want a function to return different values when you call it, you can do two things. First, you can pass it different parameters. This isn't possible for your design of from_fun--the parameter to the function is always (). Second, your function can be impure. I.e., the function can maintain some mutable state.
Here is an example of a generator:
let range_generator from below step =
let counter = ref from
in fun () ->
if (!counter < below)
then (let result = (Some !counter) in
counter := !counter + step;
result)
else None
For example, a call to range_generator 0 10 2 returns a closure over an internal counter mutable variable which generates all natural even numbers below 10:
# let gen = range_generator 0 10 2;;
val gen : unit -> int option = <fun>
Each call to gen possibly mutates the internal counter:
# gen();;
- : int option = Some 0
# gen();;
- : int option = Some 2
# gen();;
- : int option = Some 4
# gen();;
- : int option = Some 6
# gen();;
- : int option = Some 8
# gen();;
- : int option = None
# gen();;
- : int option = None
With your function:
# from_fun (range_generator 0 5 1);;
- : int list = [0; 1; 2; 3; 4]
The variable x you are using is local to the anonymous function you are using. As a result the function always return Some 1.
What you probably wanted to do is for the function to take an argument:
let rec from_fun f n =
match f n with
| None -> Nil
| Some e -> Cons(e, from_fun f e)
let seq = from_fun (fun x -> if x<10 then Some (x+1) else None) 0
EDIT:
Here is a solution with the appropriate type signature:
let rec from_fun f () =
match f () with
| None -> Nil
| Some e -> Cons(e, from_fun f ())
let x = ref 0
let seq = from_fun
(fun () ->
let v = !x in
if v < 10
then begin
x := v + 1;
Some v
end
else None)
()
It is worth noting that because of the side effects, you would have to reinitialise x before building a new sequence. The unit argument passed in parameter to from_fun is unnecessary, you could remove it.

Haskell list comprehension 0's and 1's

I am trying to write a function
row :: Int -> Int -> [Int]
row n v
that returns a list of n integers, all 0's, except for the vth element, which needs to be a 1.
For instance,
row 0 0 = []
row 5 1 = [1,0,0,0,0]
row 5 3 = [0,0,1,0,0]
I am new to Haskell and having a lot of difficulty with this. In particular I can't figure out how to make it repeat 0's. I understand the concept of building a list from let's say [1..n], but I just get [1,2,3,4,5]
Any help with this would be greatly appreciated. Thank you.
Try:
let row n v = map (\x -> if x == v then 1 else 0) [1..n]
Here a "monadic" solution:
row n v = [(v-1, 0), (1, 1), (n-v, 0)] >>= (uncurry replicate)
The replicate function repeats a given value a number of times, e.g. replicate (v-1) 0 gives a list of v-1 zeros. The uncurry is used to modify the replicate in order to accept a tuple instead of two single arguments. The funny operator >>= is the heart of a monad; for lists it is the same as concatMap with flipped arguments.
With a comprehensive list :
row n v = [if x == v then 1 else 0 | x <- [1..n]]
Or using fromEnum (thanks dave4420)
row n v = [fromEnum (x == v) | x <- [1..n]]
This should also work:
row n v = replicate (v-1)­ 0 ++ [1] ++ repl­icate (n-v)­ 0
And yet another solution, recursively building up the list:
row :: Int -> Int -> [Int]
row 0 _ = []
row n 1 = 1 : (row (n-1) 0)
row n m = 0 : (row (n-1) (m-1))
And a more readable one, where zeros are "taken":
row :: Int -> Int -> [Int]
row 0 _ = []
row n m = take (m - 1) zeros ++ [1] ++ take (n - m) zeros
where zeros = (iterate id 0)
A simple recursive loop with two temporary variables c and lst . c is for counting and lst is list which we have to return.
row :: Int -> Int -> [ Int ]
row 0 0 = []
row n v = rowHelp n v 1 [] where
rowHelp n v c lst
| c > n = lst
| v == c = rowHelp n v ( c + 1 ) ( lst ++ [ 1 ] )
| otherwise = rowHelp n v ( c + 1 ) ( lst ++ [ 0 ] )
~
~
the fun with haskell is that it let's you write your program very much the way you would express the algorithm. So try:
row n v = [if (x `mod` v==0) then 1 else 0 | x <- [1..n] ]
At first you create a list from 1,2 to n.
Then you check if the number is divisible by v, if it is, 1 is inserted in the output list, if not 0.
Examples:
> row 0 0
[]
> row 5 1
[1,0,0,0,0]
> row 5 3
[0,0,1,0,0]
> row 15 3
[0,0,1,0,0,1,0,0,1,0,0,1,0,0,1]
HTH Chris
I like to demonstrate a top down approach, based on Chris's solution:
row n v = result
where
result = take n numbers -- our result will have a length of n
numbers = map trans [1,2,..] -- and is some transformation of
-- the list of natural numbers
trans e
| e `mod` v == 0 = 1 -- let every v-th element be 1
| otherwise = 0 -- 0 otherwise
This style emphasizes the idea in functional programming that one writes down what a certain value like row n v is supposed to be, rather than trying to write down what a function does. In reminiscence of a well known joke about the lesser known pragramming language Sartre one could say that in pure functional programming functions do nothing, they just are.