I got the following piece of code which I know that works but I am completely new to Haskell and got 2 questions about the where clause.
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status --- Base Case
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail status --- Case 1
| status !! (p2-1) == 1 = f3 tail newStatus1 --- Case 2
| otherwise = f3 tail newStatus2 --- Case 3
where newStatus1 = set status p1 0 --- Line 7
newStatus2 = set newStatus2Temp p1 1 --- Line 8
newStatus2Temp = set status p2 0 --- Line 9
So basically the f3 predicate has 2 arguments :
A list of Integer lists like so : [[1,2],[2,3],[3,2]]
An Integer list
It's output is the final updated second argument.
As you see besides the base case I got 2 cases (2) and (3) where the status/[Int] argument via a standard set predicate.
Question 1) :
Say case 2 is true. Does Haskell execute lines 8 and 9 ?
Say case 3 is true. Does Haskell execute line 7?
Question 2) :
Can a guard have it's own where?
Is there a better way to actually do this?
As a result of lazy evaluation, the code in each of lines 7-9 is only run if the value of the corresponding binding is evaluated/used in the course of evaluation of code for the case that matches. So:
If case 1 is true, none of lines 7-9 are run.
If case 1 is false but case 2 is true, then evaluation of newStatus runs line 7, but lines 8-9 are not run.
If cases 1 and 2 are false but case 3 is true, then evaluation of newStatus2 runs line 8 which evaluates newStatus2Temp causing line 9 to run. Line 7 is not run.
The where clauses themselves can only be attached to entire pattern bindings (e.g., the whole f3 ([p1,p2]:tail) status | ... | ... = ... expression), not individual guards, so a guard can't have its own where clause. You could either repeat the pattern for each guard:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status | status !! (p1-1) == 0 = f3 tail status
f3 ([p1,p2]:tail) status | status !! (p2-1) == 1 = f3 tail newStatus1
where newStatus1 = set status p1 0
f3 ([p1,p2]:tail) status | otherwise = f3 tail newStatus2
where newStatus2 = set newStatus2Temp p1 1
newStatus2Temp = set status p2 0
or use let ... in ... blocks:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail status
| status !! (p2-1) == 1
= let newStatus1 = set status p1 0
in f3 tail newStatus1
| otherwise
= let newStatus2 = set newStatus2Temp p1 1
newStatus2Temp = set status p2 0
in f3 tail newStatus2
I don't think there's anything wrong with your where-clause version, and it's not unusual to write Haskell code where only a subset of the bindings in the where-clause are used (or even valid/meaningful) for each case. With such small helpers, this specific example might be more clearly written without any helpers though:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail $ status
| status !! (p2-1) == 1 = f3 tail $ set status p1 0
| otherwise = f3 tail $ set (set status p2 0) p1 1
With GHC and -O2, all four of these (your original code and these three variants) compile to identical low-level code, so use whichever you think is clearest.
Related
I have the following Haskell code:
f :: Int -> Int
f x =
let var1 = there in
case (there) of
12 -> 0
otherwise | (there - 1) >= 4 -> 2
| (there + 1) <= 2 -> 3
where there = 6
The function alone is garbage, ignore what exactly it does.
I want to replace the guards with if
f x =
let var1 = there in
case (there) of
12 -> 0
otherwise -> if (there - 1) >= 4 then 2
else if (there + 1) <= 2 then 3
where there = 6
I tried moving the if to the next line, the then to the next line, lining them up, unlining them, but nothing seems to work.
I get a parsing error and I don't know how to fix it:
parse error (possibly incorrect indentation or mismatched brackets)
|
40 | where there = 6
| ^
You have a few misunderstandings in here. Let's step through them starting from your original code:
f x =
A function definition, but the function never uses the parameter x. Strictly speaking this is a warning and not an error, but most code bases will use -Werror so consider omitting the parameter or using _ to indicate you are explicitly ignoring the variable.
let var1 = there in
This is unnecessary - again you are not using var1 (the below used there) so why have it?
case (there) of
Sure. Or just case there of, not need for excessive parens cluttering up the code.
12 -> 0
Here 12 is a pattern match, and it's fine.
otherwise ->
Here you used the variable name otherwise as a pattern which will uncondtionally match the value there. This is another warning: otherwise is a global value equal to True so it can be used in guards, such as function foo | foo < 1 = expr1 ; | otherwise = expr2. Your use is not like that, using otherwise as a pattern shadows the global value. Instead consider the catch all pattern with underscore:
_ -> if (there - 1) >= 4
then 2
else if (there + 1) <= 2
then 3
where there = 6
Ok... what if there was equal to 3? 3-1 is not greater than 4. 3+1 is not less than 2. You always need an else with your if statement. There is no if {} in Haskell instead there is if ... else ... much like the ternary operator in C, as explained in the Haskell wiki.
I've been practicing Haskell as part of my course at my university, and I made the following function while experimenting with local definitions :
fac1 x | x == 0 = zero
| x == 1 = one
| otherwise = x * fac1 (x-1)
where zero = 0
one = 1
I would expect any call to fac1 result in zero because when x==0, it will multiply by 0. However, it gives me the correct number.
Conversely, writing one = 0 instead of one = 1 results in my results being 0. I would expect the same sort of behavior for zero, but changing the value of it does nothing. I feel like it should be happening since I clearly included a x==0 condition. The x==1 is evaluated, why not x==0?
Can someone explain what error I made?
Your recursion stops on x = 1, not x = 0.
Let's evaluate fac1 2 by hand:
fac1 2
= 2 * fac1 (2 - 1) -- 2 is neither 0 nor 1, so we take the "otherwise" case
= 2 * fac1 1 -- evaluate 2 - 1
= 2 * one -- x == 1 holds, so we return "one"
= 2 * 1 -- one is 1
= 2 -- done
Basically, I have a loop that checks how many 'e' a user entered in one line. The thing is, I want it to show the total of e's entered total after every lines. Let's say he enters one line with 1 'e' in it the result will be 1, then after he enters the 2nd line that has 2 'e' in it, the total would be 3… and so on until the line is empty.
Here is my code so far. The problem with it: I don't know how to make a "total". I'm not sure if I'm clear... The current code will give the amount of 'e' found in each lines but not the total.
main = do
putStrLn "Enter your line"
line <- getLine
if line == ""
then return ()
else do
let v = nume line
main
print v
nume [] = 0
nume (x:xs)
|x == 'e' = 1 + nume xs
| otherwise = nume xs
Result:
Enter your line
there is 3 e
Enter your line
there are 4 e
Enter your line
only 1 e
Enter your line
1 <<-- Should be 8 (3+4+1)
4 <<-- Should be 7 (4+3)
3 <<-- ok
Somehow you need to add the accumulation. The simplest change would probably be to factor out the recursive action and parameterize over the total, which is initially 0. Something like this:
inner n = do
putStrLn "Enter your line"
line <- getLine
if line == ""
then return ()
else do
let v = n + nume line
inner v
print v
main = inner 0
nume [] = 0
nume (x:xs)
|x == 'e' = 1 + nume xs
| otherwise = nume xs
I have been trying to create a function in Haskell that will take a non-negative value which corresponds to minutes and return it in the format (days,hours,minutes) e.g. 4000 minutes will give (2, 18, 39).
My code keeps returning the error "file:.\prac0.hs:27 - Syntax error in input (unexpected `|')" on load.
Here is my code:
dayshoursmins :: Int->(Int,Int,Int)
dayshoursmins n = (x,y,z)
| n==0 = 0
| n`div`1440 =>1 = x && dayshoursmins(n`mod`1440)
| n`div`60 < 24 = y && dayshoursmins(n`mod`60)
| n < 60 = z
The pipe (|) is used as a guard, what you need is a where clause I think:
dayshoursmins :: Int->(Int,Int,Int)
dayshoursmins n = (d,h,m)
where d = div n 1440
dm = mod n 1440
h = div dm 60
m = mod dm 60
Running this with ghci gives:
*Main> dayshoursmins 2016
(1,9,36)
I don't really understand your code: it does seem to mix all kinds of concepts. After the = operator, you cannot put guards anymore.
Here I am trying to find the index of '-' followed by '}' in a String.
For an input like sustringIndex "abcd -} sad" it gives me an output of 10
which is giving me the entire string length.
Also if I do something like sustringIndex "abcd\n -} sad" it gives me 6
Why is that so with \n. What am I doing wrong. Please correct me I'm a noob.
substrIndex :: String -> Int
substrIndex ""=0
substrIndex (s:"") = 0
substrIndex (s:t:str)
| s== '-' && t == '}' = 0
| otherwise = 2+(substrIndex str)
Your program has a bug. You are checking every two characters. But, what if the - and } are in different pairs, for example S-}?
It will first check S and - are equal to - and } respectively.
Since they don't match, it will move on with } alone.
So, you just need to change the logic a little bit, like this
substrIndex (s:t:str)
| s == '-' && t == '}' = 0
| otherwise = 1 + (substrIndex (t:str))
Now, if the current pair doesn't match -}, then just skip the first character and proceed with the second character, substrIndex (t:str). So, if S- doesn't match, your program will proceed with -}. Since we dropped only one character we add only 1, instead of 2.
This can be shortened and written clearly, as suggested by user2407038, like this
substrIndex :: String -> Int
substrIndex [] = 0
substrIndex ('-':'}':_) = 0
substrIndex (_:xs) = 1 + substrIndex xs