Why is a part of my where clause not used in my conditional function? - haskell

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

Related

What is the meaning of "range( i + 1 )"?

I have a question ,what is the meaning of "range( i + 1 )" below ,if I want to show the output which has xyyzzz?
a = ("x", "y", "z")
for i in range(len(a)):
for j in range( i + 1):
print(a[i])
output: x
y
y
z
z
z
I tried to explain this to you with values
i = 0 ---> j = range(1) = 0 : a[0] = x
--------------------------------
i = 1 ----> j =range(2) = (0,1) : a[1] = y
: a[1] = y
-----------------------------------------
i = 2 ----> j = range(3) = (0,1,2) : a[2] = z
: a[2] = z
: a[2] = z
range(n) gives you values from 0 to n-1.
If you are unfamiliar with Python currently, this can be represented in different ways:
In mathematical interval notation, you can represent this as [0,n) . The left value is included, and the right one is excluded.
Taking len(a) to be 3, the above for loops would be written in C as:
for (int i = 0 ; i < 3 ; ++i){
for (int j = 0 ; j <= i ; ++j){ // note the <= . We can also do j < (i+1)
...
}
}
Your code first calculates len(a), which is 3, since this is a container with 3 elements (this specific container is called a tuple). The first for loop goes from 0 to 2, while the second for loop goes from 0 to wherever the counter of the outer for loop is at (less than or equal to). This causes the first value to be printed just once, next twice, and the last one thrice.
(If you want to test your understanding further, try to figure out what would be printed if we had print(a[j]) inside the loops rather than a[i].)
range() is a versatile and powerful thing in Python, it can do much more than just give you values from 0 to n-1. Do read about it if you intend to use Python.

Why isn't my for loop working, but my while loop is?

[Sorry in advance, I'm very new to programming.]
This is for project euler problem #2. The goal is to calculate the sum of all even fibonacci numbers that do not exceed 4 million. For anyone not familiar with fibonacci numbers, a fibonacci number is simply a number that is the sum of the two previous numbers in the sequence. For example, the first few fibonacci numbers are 1,2,3,5,8,13,21,34 ...
My code is below beginning with some variables, then my while loop, and finally my for loop.
n = 0
n2 = 1
fibsum = 0
fibrange = range(1,4000001)
while (n2 <= 4000000):
n2 = n2 + n
n = n2 - n
if n2 % 2 == 0:
fibsum += n2
print (fibsum)
# for n2 in fibrange:
# n2 = n2 + n
# n = n2 - n
# if n2 % 2 == 0:
# fibsum += n2
# print(fibsum)
As I said, my while loop works like a charm, but when I run the for loop the output of fibsum is 0. So the value is not changing at all.
I've tried range (1, 4000001) in place of fibrange. I really have no idea what else to try. This is like my 4th or 5th program ever.
Using for loop in range function, The Value of the variable n2 changes according only to range function.You cannot manually change the variable in for loop while using range function.
for and while and are different types of loops.
while: Repeats a statement or group of statements while a given condition is TRUE. It tests the condition before executing the loop body.
for: Executes a sequence of statements multiple times and abbreviates the code that manages the loop variable.
With while you can do something like this:
a = 0
b = 1
target = 4000000
result = 0
while a <= target:
if a % 2 == 0:
result +=a
a, b = b, a + b
print(result)
With for:
a, b = 0, 1
result = 0
target = 4000000
fib_sequence = 35 # -> the length of fibonacci sequence
for _ in range(fib_sequence):
if a % 2 == 0:
result +=a
a, b = b, a + b
if a >= target: break
print(result)

How to fix indentation problem with haskell if statement

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.

Error specified for negative numbers displayed when function applied to a Fractional. Why?

I am trying to learn Haskell, and I defined the following simple recursive function to calculate the factorial.
fact n | n < 0 = error "fact only valid for non-negative integers"
| n == 0 = 1
| n > 0 = n * fact(n-1)
It works fine for a positive integer, and as expected when invoked with a negative integer, it throws the error that I have specified.
What is the problem?: It gives me the same error ("fact only valid for non-negative integers") when I try to apply it to a Fractional, such as fact 10.5. Why does it give me that same error that I have clearly specified should apply for only the case of n < 0.
If you give it 10.5 as argument, then the third case is valid, and the function calls itself recursively with n = 10.5 - 1 = 9.5.
That input also triggers the third case, making a recursive call with n = 8.5.
And so on: 7.5, then 6.5, then 5.5, 4.5, 3.5, 2.5, 1.5, 0.5
And then, on the next iteration, n = -0.5, which triggers the first case and produces the error. Everything exactly as coded.
If you want your function to work for fractional numbers, you have to (a) define what is a factorial of n for 0 < n < 1, and then (b) encode that case.
For example, if I were to define factorial of a number between zero and one to be equal to one, then the function would look like this:
fact n | n < 0 = error "fact only valid for non-negative integers"
| n >= 0 && n <= 1 = 1
| n > 0 = n * fact(n-1)
Also, a side note: I think the above code should give you a warning that the function is partial. This is because the compiler cannot prove that one of the cases should always hold (and in all fairness, depending on the argument type and the definition of Num and Ord for it, it might not hold). To avoid this, one should use an otherwise clause:
fact n | n < 0 = error "fact only valid for non-negative integers"
| n >= 0 && n <= 1 = 1
| otherwise = n * fact(n-1)

Error in Haskell code containing tuples

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.

Resources