Haskell - Parameter count that fit criteria? - haskell

Let's say I have a function:
isOne :: Int -> Int -> Int
isOne x y =
Then if x == 1 and y != 1 then it returns 1 (one of the parameters equals 1), if x == 1 and y == 1 it returns 2 (because both are 1), if x != 1 and y != 1 it returns 0 etc.
I can't figure out how to do more than a single check with an if statement (or using cases).

Why, you just need to translate your english to Haskell:
if (x==1) && (y /= 1) then 1
else if (x/=1) && (y==1) then 1
...
But you really want:
isOne 1 1 = 2
isOne 1 _ = 1
isOne _ 1 = 1
isOne _ _ = 0
or, even shorter:
isOne x y = fromEnum (x==1) + fromEnum (y==1)

The easiest way to this is with pattern matches. You can define a function by cases, which are interpreted in the order at which they occur
isOne 1 1 = 2
isOne 1 _ = 1
isOne _ 1 = 1
isOne _ _ = 0
alternatively, you can use guards
isOne x y | (x == 1) && (y == 1) = 2
| (x == 1) && (y != 1) = 1
| (x != 1) && (y == 1) = 1
| otherwise = 0
again, these are checked from top to bottom. That is, if the first guard matches then it goes with the first equation, otherwise it tries the second, and so on. This can also be written
isOne x y | (x == 1) && (y == 1) = 2
isOne x y | (x == 1) && (y != 1) = 1
isOne x y | (x != 1) && (y == 1) = 1
isOne x y | otherwise = 0
or
isOne x y | (x == 1) && (y == 1) = 2
isOne x y | (x == 1) || (y == 1) = 1
isOne x y | otherwise = 0
another way of doing it would be to use an if then else expression.
isOne x y = if (x == 1) && (y == 1)
then 2
else if (x == 1) || (y == 1) then 1 else 0
or perhaps you could try doing
isOne x y = (go x) + (go y) where
go 1 = 1
go _ = 0
or any of dozens of other ways...

Method 1
Use paired case statements
isOne x y = case (x, y) of
(1, 1) -> 2
(1, _) -> 1
(0, 0) -> 0
...
Method 2
Use nested if statements
isOne x y = if x == 1 then (if y == 1 then 2 else 1) else 0

I'd second using either direct pattern matching in the function definition, or case on tuples.
But the most readable alternative would IMO be length [ q | q<-[x,y], q==1 ].

Related

Show result in Haskell

I'm very new to haskell.
How can I return (x1,x2) and print it out from my code?
qqq x
| x < 0 x1 = mod (-x) 10
| 1 < x && x < 99 x1 = mod x 10
| x2 = mod x 10
You are using guards the wrong way. You seem to see these as if statements, that you then can use for assignements. In Haskell, you do not assign values to a variable, you declare these. You can work with:
qqq :: Integral a => a -> (a, a)
qqq x
| x < 0 = (mod (-x) 10, x2)
| 1 < x && x < 99 = (mod x 10, x2)
where x2 = mod x 10
Here each guard thus has a condition before the equation sign (=), and at the right side returns a 2-tuple with as first item an expression for x1, and as second item x2.
You should also implement extra case(s) for x == 1 and x >= 99, these are not covered by the two guards.

Write a function that lists numbers from n to m by k number of steps. If the step size is negative list them in descending order

Implement the interval2 :: Int -> Int -> Int -> [Int] function,that lists numbers from the first parameter to the third parameter, the stepping's size is the second parameter. Using [n..m], [n,k..m] or [n..] is prohibited.
For example:
interval2 1 1 10 == [1,2..10]
interval2 10 1 0 == [10,11..0]
interval2 10 (-1) 0 == [10,9..0]
interval2 1 2 10 == [1,3..10]
interval2 10 2 0 == [10,12..0]
interval2 0 (-2) (-10) == [0,(-2)..(-10)]
interval2 1 (-1) 10 == [1,0..10]
interval2 0 (-10) (-1000) == [0,(-10)..(-1000)]
So far, I've managed to write some cases, but they didn't do the job very well.
interval2 x y z | x < z && y > 0 = [x] ++ interval2 (x+y) y z
| x < z && y < 0 = [x] ++ interval2 (x-y) y z
| x > z && y > 0 = [x] ++ interval2 (x-y) y z
| x > z && y < 0 = [x] ++ interval2 (x+y) y z
| x == z || x > z = [z]
There are basically two cases when you should emit a new value:
if x <= z and y > 0; and
if x >= z and y < 0.
In both cases that means the list contains x as first element and should recurse on the interval with x+y. In case none of these conditions are not met, then we have reached the end of the list.
This thus means that the function looks like:
interval2 x y z
| (x <= z && y > 0) || (x >= z && y < 0) = …
| otherwise = …
where I leave implementing … as an exercise.
Naming is important. When learning, naming is very important.
What is x? What is y? What is z? Are all of them the same, conceptually?
No, as the exercise describes it, it is
interval2 :: Int -> Int -> Int -> [Int]
interval2 from stepSize to =
this already gets you half way there towards the solution. Yes it does.
Or actually, you have a contradiction. According to the title of your post, it is
interval2b :: Int -> Int -> Int -> [Int]
interval2b from numSteps to =
But in any case, solving the first one first, you seem to get lost in the multitude of tests. Instead of doing all of them in one function, why not do a test to decide which of several functions to use to do the job; then write each of those functions being already able to assume certain things, namely those which we've tested for:
interval2 from stepSize to
| stepSize > 0 = increasing from
| stepSize < 0 = decreasing from
| otherwise = []
where
increasing from
| from
and now it is easy to see which test to perform here, isn't it?
> to = []
| otherwise = from : increasing ....
decreasing from
| from
and similarly here.
.........
..................
I hope this helps you manage this complexity so you'll be able to complete this code yourself.

Recursive addition in Haskell

The problem:
You are given a function plusOne x = x + 1. Without using any other (+)s, define a recursive function addition such that addition x y adds x and y together.
(from wikibooks.org)
My code (it does not work -- endless loop):
plusOne x = x + 1
addition x y
| x > 0 = addition (plusOne y) (x-1)
| otherwise = y
Questions:
How to connect the plusOne function to the addition recursive function?
How should it be written?
You are mixing up x and y in your recursive case
addition x y | y > 0 = addition (plusOne x) (y - 1) -- x + y == (x + 1) + (y - 1)
| otherwise = x -- x + 0 = x
using == and 0
addition = add 0 where
add a y x | a == y = x
| otherwise = add (plusOne a) y (plusOne x)

why do I get a type error here?

I'm sitting on this for over 4 hours and can't wrap my head aroud it.
I try to run the following code:
top = 100 :: Int
couplesToOne num
|num<0 = error "num<0"
|num==0 = 0
|num `mod` 2 == 0 = num `div` 2
|num `mod` 2 == 1 = (num+1) `div` 2
|otherwise = error "otherwise"
numInBig n bigSide
|(bigSide^2 <= n) = couplesToOne (n-1)
|(bigSide^2 > n) = couplesToOne (n-1) - (couplesToOne (floor(sqrt(bigSide^2 - n))))
|otherwise = error "otherwise"
ans = map (numInBig top) [3..((div top 4) + 1)]
and I get the following error message:
No instance for (RealFrac Int) arising from a use of `numInBig'
In the first argument of `map', namely `(numInBig top)'
In the expression: map (numInBig top) [3 .. ((div top 4) + 1)]
In an equation for `ans':
ans = map (numInBig top) [3 .. ((div top 4) + 1)]
enter code here
I figured out (probably?) that this is because of the "sqrt" that returns a float but that's why I added the floor that's supposed to return an Integral.
can you please help me?
This works:
top = 100 :: Int
couplesToOne num
|num<0 = error "num<0"
|num==0 = 0
|num `mod` 2 == 0 = num `div` 2
|num `mod` 2 == 1 = (num+1) `div` 2
|otherwise = error "otherwise"
numInBig n bigSide
|(bigSide^2 <= n) = couplesToOne (n-1)
|(bigSide^2 > n) = couplesToOne (n-1) - couplesToOne (floor(sqrt(fromIntegral(bigSide^2 - n))))
|otherwise = error "otherwise"
ans = map (numInBig top) [3..((div top 4) + 1)]
You need an extra fromIntegral because sqrt::Floating a => a -> a is not defined on Int.
> ans
[50,50,50,50,50,50,50,50,48,47,46,45,44,44,43,43,42,41,41]

Infinite loop in recursive Haskell function

Hmm... why does this function ends in an infinite loop when evaluating for any integer > 3?
smallestMultiple n = factors [2..n] where
factors [] = []
factors (h:xs) = h:(factors $ filter ((<)1) [div x h|x<-xs])
where
div x y
|x `mod` y ==0 = x `div` y
|otherwise = x
It appears that the main problem is that you define a local version of div:
div x y
| x `mod` y == 0 = x `div` y
| otherwise = x
Since bindings in where clauses (as well as in let) are recursive, the div on the right hand side of the first case refers to the same div you're defining! You can fix this by using a different name, like div':
div' x y
| x `mod` y == 0 = x `div` y
| otherwise = x

Resources