about the use of "case of" in Haskell - haskell

I think case of is quite straight forward, as i come from more imperative languages.
Nevertheless, i have encountered a Kata where one of the solutions by another user, confuses me about the use of case and Data.List (sort)
import Data.List (sort)
isTriangle :: Int -> Int -> Int -> Bool
isTriangle a b c =
case sort [a,b,c] of
[min, middle, max] -> (min + middle) > max
By definition, 3 segments can make a triangle if the condition a + b > c is met for the 3 permutations of [a,b,c] so, something more straight forward (my answer) would be:
isTriangle :: Int -> Int -> Int -> Bool
isTriangle a b c = a + b > c && b + c > a && a + c > b
My question is, in the case above, how is the case of testing that condition for the 3 combinations?

Imagine that a b and c are ordered from small to large, then the algorithm tests that a + b > c, which is what the first implementation checks.
If we know that a < b < c, and a + b > c holds, then we know that a + c > b holds. Indeed: a + c > a + b > c > b, hence a + c > b holds because a + b > c holds. Furthermore b + c > a + b > c > a holds, and thus b + c > a holds as well.
This thus means that checking if it holds for a known minimum, maximum and value in between, the two other equations are implied.
What the case … of does here is sorting the list [a, b, c] and unpacking the sorted list in min, middle and max, it is thus a tool that is used to assign the smallest value to min, the largest value to max and the remaining value to middle. A where … or let … in … is probably more elegant, for example:
isTriangle :: Int -> Int -> Int -> Bool
isTriangle a b c = (min + middle) > max
where [min, middle, max] = sort [a, b, c]

Related

Linear recursive method for counting palindrome numbers between 2 integers in Haskell

I'm solving a practice problem in Haskell where I'm trying to count the palindrome numbers between 2 given integers. Single-digit numbers are palindromes. I've tried solving it with a helper function but I can't make it take the smaller number from the main function. Any help would be appreciated!
So far I typed this:
main :: IO()
main = do
print $ countPalindromes 5 13 == 5 -- 6 7 8 9 11
print $ countPalindromes 13 5 == 5 -- 6 7 8 9 11
rev :: Int -> Int
rev n = helper n 0
where
helper :: Int -> Int -> Int
helper 0 result = result
helper n result = helper (div n 10) (result * 10 + mod n 10)
isPalindrome :: Int -> Bool
isPalindrome x = rev x == x
countPalindromes :: Int -> Int -> Int
countPalindromes a b
| a > b = helper b a 0
| otherwise = helper a b 0
where
helper :: Int -> Int -> Int -> Int
helper a b count
| a <= b && isPalindrome (a - 1) = count + 1
| otherwise = helper (a - 1) b count
That's not your problem. The problem is that helper a b count only returns count + 1 if a is a palindrome, without ever checking if a + 1, a + 2, etc, are palindromes as well. When the first number is a palindrome, it returns 0 + 1 == 1 and done. (Your definition of helper is also counting the wrong way; it's decrementing a instead of incrementing as you need to do if you ever want a <= b to be false.)
helper needs to recurse whether or not a is a palindrome; the only difference is in the value of its third argument.
helper a b count | a > b = count -- base
| isPalindrome a = helper (a + 1) b (count + 1)
| otherwise = helper (a + 1) b count
Note that b never changes; it doesn't need to be an argument to helper. Instead, you can make a recursive call to countPalindromes to ensure a < b:
countPalindromes :: Int -> Int -> Int
countPalindromes a b
| a > b = countPalindromes b a
| otherwise = helper a 0
where
helper :: Int -> Int -> Int
helper a count
| a > b = count -- base case
| isPalindrom a = helper (a + 1) (count + 1)
| otherwise = helper (a + 1) count
Tail recursion also isn't terribly important in Haskell. You can write helper more naturally
helper a | a > b = 0
| isPalindrome a = 1 + helper (a + 1)
| otherwise = helper (a + 1)
Note, too, that the only difference between isPalindrome returning True or False is whether you add 1 or 0 to the recursive return value. You can capture that with fromEnum:
helper a | a > b = 0
| otherwise = (fromEnum (isPalindrome a)) + helper (a + 1)
As an exercise, note that you don't need explicit recursion at all. You can use filter to get the values in range that are palindromes, then simply count the number of values in the resulting list.

Haskell, Local definition and variables, confused :/

f0 :: Int -> Int -> Int -> Int
f0 a b c = x a b - x a c - x b c
where x b a = a + b
Can someone explain me how the functions knows what to do when it gets to the...
where x b a = a + b
... statement? Does it just translate to something like this?
f0 a b c = (a + b) a b - (a + b) a c - (a + b) b c
[...] or is it just that the "x" is just another functions which takes two variables and add them [...]
Exactly. x b a = a + b is a function definition (that happens to have local scope). f0 0 0 1 = x 0 0 - x 0 1 - x 0 1. – duplode
In some other pseudo language this will look like this.
int function fo(int a, int b, int c){
int function x(int a, int b){
return a + b;
}
return x(a,b) - x(a,c) - x(b,c)
}
The way you have put it as a question,
f0 a b c = (a + b) a b - (a + b) a c - (a + b) b c
it looks like inline substitution like C macros. It is not simple code substitution. It is more like inline function. X is a function which gets called.

Is it possible to generalise equations in Haskell?

Apologies for my poor wording of the question. I've tried searching for an answer but not knowing what to search is making it very difficult to find one.
Here is a simple function which calculates the area of a triangle.
triangleArea :: Float -> Float -> Float -> Float
triangleArea a b c
| (a + b) <= c = error "Not a triangle!"
| (a + c) <= b = error "Not a triangle!"
| (b + c) <= a = error "Not a triangle!"
| otherwise = sqrt (s * (s - a) * (s - b) * (s - c))
where s = (a + b + c) / 2
Three lines of the function have been taken up for the purposes of error checking. I was wondering if these three lines could be condensed into one generic line.
I was wondering if something similar to the following would be possible
(arg1 + arg2) == arg3
where Haskell knows to check each possible combination of the three arguments.
I think #behzad.nouri's comment is the best. Sometimes doing a little math is the best way to program. Here's a somewhat overdone expansion on #melpomene's solution, which I thought would be fun to share. Let's write a function similar to permutations but that computes combinations:
import Control.Arrow (first, second)
-- choose n xs returns a list of tuples, the first component of each having
-- n elements and the second component having the rest, in all combinations
-- (ignoring order within the lists). N.B. this would be faster if implemented
-- using a DList.
choose :: Int -> [a] -> [([a],[a])]
choose 0 xs = [([], xs)]
choose _ [] = []
choose n (x:xs) =
map (first (x:)) (choose (n-1) xs) ++
map (second (x:)) (choose n xs)
So..
ghci> choose 2 [1,2,3]
[([1,2],[3]),([1,3],[2]),([2,3],[1])]
Now you can write
triangleArea a b c
| or [ x + y <= z | ([x,y], [z]) <- choose 2 [a,b,c] ] = error ...
This doesn't address the question of how to shorten your error checking code, but you may be able to limit how often you repeat it by defining some new types with invariants. This function needs error checking because you can't trust the user to supply Float triples that make a reasonable triangle, and if you continue to define functions this way then every triangle-related function you write would need similar error checks.
However, if you define a Triangle type, you can check your invariants only once, when a triangle is created, and then all other functions will be guaranteed to receive valid triangles:
module Triangle (Triangle(), mkTriangle, area) where
data Triangle a = Triangle a a a deriving Show
mkTriangle :: (Num a, Ord a) => a -> a -> a -> Either String (Triangle a)
mkTriangle a b c
| a + b <= c = wrong
| a + c <= b = wrong
| b + c <= a = wrong
| otherwise = Right $ Triangle a b c
where wrong = Left "Not a triangle!"
area :: Floating a => Triangle a -> a
area (Triangle a b c) = sqrt (s * (s - a) * (s - b) * (s - c))
where s = (a + b + c) / 2
Here we export the Triangle type, but not its constructor, so that the client must use mkTriangle instead, which can do the required error checking. Then area, and any other triangle functions you write, can omit the checks that they are receiving a valid triangle. This general pattern is called "smart constructors".
Here are two ideas.
Using existing tools, you can generate all the permutations of the arguments and check that they all satisfy a condition. Thus:
import Data.List
triangleArea a b c
| any (\[x, y, z] -> x + y <= z) (permutations [a,b,c])
= error "Not a triangle!"
| otherwise = {- ... -}
This doesn't require writing very much additional code; however, it will search some permutations you don't care about.
Use the usual trick for choosing an element from a list and the left-overs. The zippers function is one I use frequently:
zippers :: [a] -> [([a], a, [a])]
zippers = go [] where
go b [] = []
go b (v:e) = (b, v, e) : go (v:b) e
We can use it to build a function which chooses only appropriate triples of elements:
triples :: [a] -> [(a, a, a)]
triples xs = do
(b1, v1, e1) <- zippers xs
(b2, v2, e2) <- zippers e1
v3 <- b1 ++ b2 ++ e2
return (v1, v2, v3)
Now we can write our guard like in part (1), but it will only consider unique pairings for the addition.
triangleArea a b c
| any (\(x, y, z) -> x + y <= z) (triples [a,b,c])
= error "Not a triangle!"
| otherwise = {- ... -}

Haskell take sum recursively

Hello I want to take a sum of functions call in Haskel but I cannot figure out what I am doing wrong. To be more specific, I have a function f(a,b,c)=a+b+c and I want to take an int like this:
x=Sum( from i=0 to i=c) f(1,1,i)
so far I have written this, but it doesn't even compile. Can you help me?
f a b c = a+b+c
my_sum f a b c+1 =f a b c+1 + my_sum f a b c
I get parse error in pattern my_sum
eg for my_sum f 1 1 5 the result would be f(1,1,5)+f(1,1,4)+f(1,1,3)+f(1,1,2)+f(1,1,1)
I dont want to use lists
n+k patterns are bad
Your code:
my_sum f a b c+1 =f a b c+1 + my_sum f a b c
includes a pattern in the form c+1 which A) should have parentheses B) Needs a base case (I assume you want to stop when c == 0) and C) is a syntactic form that has been removed from the language.
Instead, explicitly subtract 1 from c when you want and be sure to handle the base case:
my_sum f a b 0 = f a b 0
my_sum f a b n = f a b n + my_sum f a b (n-1)
This also has a memory leak meaning it will build up a large computation in the form f1 + (f a b n' + (f a b n'' + (f a b n''' + (.... You can handle the leak by using an accumulator or a higher level function and optimization at compile-time.
A cleaner Solution
List comprehension strikes me as the most reasonable solution here:
sum [f a b i | i <- [0..c] ]
The sum of the function f applied to arugments a, b and finally i where i ranges from 0 to c inclusively.
You can't have the c+1 on the left side of a definition. Since you're just summing, it doesn't matter if you count up from 0 to c or count down from c to 0, so you could instead do
my_sum f a b 0 = f a b 0
my_sum f a b c = f a b c + my_sum f a b (c - 1)
Then you could use it as
> let g x y z = x + y + z
> my_sum g 0 0 10
55
Some more detail on why your code failed to compile: Whenever you have a pattern on the left side of a definition, such as
fib 0 = 1
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)
You can only match on constructors, names (like n or c), and literals (which are essentially constructors for the basic types). The function + is not a constructor, it is a function belonging to the Num typeclass, so therefore you can not pattern match on it. You may be confused from seeing list pattern matching before because it uses an operator:
myListSum [] = 0
myListSum (x:xs) = x + myListSum xs
but in fact, : is the Cons constructor for lists, and [] is the empty list constructor. You can think of the list type defined as
data [a] = [] | a : [a]
Or, if you were to replace all the symbols with words
data List a = Empty | Cons a (List a)
although its a bit different in reality since there's more that goes into defining lists, but that's the basic idea. This means that a pattern like
f [] = ...
f (x:xs) = ...
Is equivalent to
f Empty = ...
f (Cons x xs) = ...
just with more convenient syntax.
However, Int can be though of as a very large ADT defined as
data Int = -2147483648 | -2147483647 | ... | -1 | 0 | 1 | ... | 2147483646 | 2147483647
where each number itself is a different constructor. Then you can match on any individual number, but not anything like (x + 1) or (x * 2), because + and * are not constructors, just regular functions. (Note: Int is not actually defined this way because that would be really inefficient, it's defined at a more primitive level)
You can get from list formulations to the non-list, recursive formulations, with manual inlining and fusing of the functions in play:
{-# LANGUAGE BangPatterns #-}
import Data.List
f a b c = a+b+c
g f a b c = sum . map (f a b) $ [0..c]
= foldl' (\ !x y -> x + f a b y) 0 $ enumFromTo 0 c
= h 0 0 where
h !acc i | i > c = acc
| otherwise = h (acc + f a b i) (i+1)
Strictness annotations prevent uncontrolled build-up of thunks and stack overflow for big values of c.

How do I return the middle number in Haskell

I have the following beginning of a function, and am unsure as to how I should return Middle Number (i.e. the number that is neither the largest nor smallest):
middleNumber :: Int -> Int -> Int -> Int
middleNumber a b c
| ...
I would recommend you break the function into two steps: First, sort the three numbers. Then, take the middle element. For the first step, also consider if you can take it one step at a time; each step bringing it a bit closer to being fully sorted, then tail-recursing back to bring it even closer.
The "middle number" is larger than one of the numbers, but smaller than the other number. And there is only one middle number. The most mechanical way to solve this would be to start off
middleNumber a b c
| a < b && a > c = a
Check if a is the middle number by being less than b but greater than c.
Now what if a is the middle number, but it's actually greater than b and less than c? There's another guard. What if b is the middle number? There's another 2 guards. What if c is the middle number? There's 2 more guards, for a total of 6 different cases.
(btw, the expression | a < b && a > c = a is referred to as a guard. If you don't have a firm grasp yet of what guards are, then I recommend LYAH # Guards)
Of course there are better ways to write the function, but for understanding purposes it's good to be able to manually and systematically break down all of the possible situations, and determine what to do in each situation. How To Design Programs is a great book for learning how to be systematic in this way.
The obligatory Rube-Goldberg-answer:
import Control.Applicative
middleNumber a b c = sum $ [sum, negate.minimum, negate.maximum] <*> [[a,b,c]]
[Edit]
Here is another version:
middleNumber a b c = fst $ maximumBy (compare `on` abs.snd) [(a,b-c),(b,c-a),(c,a-b)]
I'm sure we could translate this to arrow syntax for further obfuscation, but I leave that task to the interested reader.
Expanding on Dan Burton's answer with guards, I evaluate a, b, c cases each in its own guard. However, what happens when 2 of the numbers are equal? Then the middle number should be one of the duplicated ones.
middleNumber :: Int -> Int -> Int -> Int
middleNumber a b c
| (a > b && a < c) || (a > c && a < b) = a
| (b > a && b < c) || (b > c && b < a) = b
| (c > a && c < b) || (c > b && c < a) = c
| otherwise = if a == b then a else c
I did a quick brute force method but this is most certainly not the best solution
import Data.List
middleNum :: Int -> Int -> Int -> Int
middleNum a b c = (\[_,m,_] -> m) $ sort $ a:b:c:[]
Obviously this is an awful idea as it explicitly relies on there being 3 items in the list, but it does the job
You can leverage guards and where to obtain the same result in simple way:
middleNumber :: Int -> Int -> Int -> Int
middleNumber x y z
| a == x = max y z
| a == y = max x z
| a == z = max x y
where
a = max x $ max y z
If you don't have access to the built-in max. you can easily write your own.
max' :: Int -> Int -> Int
max' x y
| x > y = x
| otherwise = y

Resources