So I'm trying to wrap my head around Haskell with my first project where i have a function encountering an error:
Exception: prelude.head: empty list.
selectNextGuess :: [[Card]] -> [Card]
selectNextGuess lst
| length lst >= 1250 = lst !! (div (length lst) 2)
| otherwise = newGuess
where fbList = [[feedback x y | x <- lst, y <- lst]]
valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x) | x <- lst]
(_, newGuess) = head(sort valuesList)
Any advice in steering me in the right direction to solve this would be greatly appreciated.
Cheers
TL;DR: since a list can be empty, and there is no minimal element in the empty list, the way to return a list without the error is to maybe return a list, or rather to return a Maybe list.
If you call selectNextGuess [], lst inside the function selectNextGuess becomes []. Then, valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x) | x <- [] ] = [] is also an empty list. And then (_, newGuess) = head (sort valuesList) = head (sort []) = head [] is called.
But there is no head element in the empty list. This is what the error message is telling us. You called head with [], which is forbidden, because it has no answer.
The usual solution is to make this possibility explicit in the data type. We either have just one answer, for a non-empty list, or we have nothing:
data Maybe a = Just a | Nothing
is such built-in type. So we can use it, and handle the empty lst explicitly:
selectNextGuess :: [[Card]] -> Maybe [Card]
selectNextGuess lst
| length lst >= 1250 = Just $ lst !! (div (length lst) 2)
| null lst = Nothing
| otherwise = Just newGuess
where fbList = [[feedback x y | x <- lst, y <- lst]]
valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x)
| x <- lst]
(_, newGuess) = head (sort valuesList)
Using null as a guard like that is a bit of an anti-pattern. We usually achieve the same goal with the explicit pattern in a separate clause, like
selectNextGuess :: [[Card]] -> Maybe [Card]
selectNextGuess [] = Nothing
selectNextGuess lst
| length lst >= 1250 = Just $ lst !! (div (length lst) 2)
| otherwise = Just newGuess
where ......
Using that head ... sort ... combination to find the minimal element is perfectly fine. Due to Haskell's lazy evaluation and the library sort being implemented as bottom-up mergesort, it will take O(n) time.
There is also a shorter way to write down the same thing,
....
| otherwise = listToMaybe . map snd $ sort valuesList -- or,
= listToMaybe [ x | (_, x) <- sort valuesList ] -- whichever you prefer.
where fbList = .....
valuesList = .....
Since there is no more than one value "inside" a Maybe _, the conversion function listToMaybe already takes just head element, implicitly.
Moreover, it produces Nothing automatically in the empty list [] case. So the explicit pattern clause can be removed, this way.
How can I create a function which lazily makes permutations for the chars '_' and '*' like this:
For example:
Main> function 3
["___","*__","_*_","__*","**_","_**","*_*","***"]
First element is made only from _, the next 3 are permutations that lists: *__, the second 3 are permutations that lists **_, and the last element contains only *.
How can I do that?
Here's another "correct order" version:
function :: Int -> [String]
function c = concatMap helper $ zip (reverse [0..c]) [0..c]
helper :: (Int, Int) -> [String]
helper (c, 0) = [replicate c '_']
helper (0, c) = [replicate c '*']
helper (cUnderscores, cAsterisks) = map ('_' :) (helper (cUnderscores - 1, cAsterisks))
++ map ('*' :) (helper (cUnderscores, cAsterisks - 1))
You might want to look at replicateM.
let k = ["_", "*"]
let p = [ a ++ b ++ c | a <- k, b <- k, c <- k ]
The “correct order” version:
import Data.List
function k = concatMap (nub . permutations . pat) [0..k]
where pat x = replicate x '*' ++ replicate (k-x) '_'
I don’t know how to step from one permutation to another in constant time, though.
I'm still learning Haskell, and I was wondering if there is a less verbose way to express the below statement using 1 line of code:
map (\x -> (x, (if mod x 3 == 0 then "fizz" else "") ++
if mod x 5 == 0 then "buzz" else "")) [1..100]
Produces:
[(1,""),(2,""),(3,"fizz"),(4,""),(5,"buzz"),(6,"fizz"),(7,""),(8,""),(9,"fizz"),(10,"buzz"),(11,""),(12,"fizz"),(13,""),(14,""),(15,"fizzbuzz"),(16,""),(17,""),(18,"fizz"),(19,""),(20,"buzz"),(21,"fizz"),(22,""),(23,""),(24,"fizz"),(25,"buzz"),(26,""),(27,"fizz"),(28,""),(29,""),(30,"fizzbuzz"), etc
It just feels like I'm fighting the syntax more than I should. I've seen other questions for this in Haskell, but I'm looking for the most optimal way to express this in a single statement (trying to understand how to work the syntax better).
We need no stinkin' mod...
zip [1..100] $ zipWith (++) (cycle ["","","fizz"]) (cycle ["","","","","buzz"])
or slightly shorter
import Data.Function(on)
zip [1..100] $ (zipWith (++) `on` cycle) ["","","fizz"] ["","","","","buzz"]
Or the brute force way:
zip [1..100] $ cycle ["","","fizz","","buzz","fizz","","","fizz","buzz","","fizz","","","fizzbuzz"]
If you insist on a one-liner:
[(x, concat $ ["fizz" | mod x 3 == 0] ++ ["buzz" | mod x 5 == 0]) | x <- [1..100]]
How's about...
fizzBuzz = [(x, fizz x ++ buzz x) | x <- [1..100]]
where fizz n | n `mod` 3 == 0 = "fizz"
| otherwise = ""
buzz n | n `mod` 5 == 0 = "buzz"
| otherwise = ""
Couldn't resist going in the other direction and making it more complicated. Look, no mod...
merge as#(a#(ia,sa):as') bs#(b#(ib,sb):bs') =
case compare ia ib of
LT -> a : merge as' bs
GT -> b : merge as bs'
EQ -> (ia, sa++sb) : merge as' bs'
merge as bs = as ++ bs
zz (n,s) = [(i, s) | i <- [n,2*n..]]
fizzBuzz = foldr merge [] $ map zz [(1,""), (3,"fizz"), (5,"buzz")]
Along the same lines as larsmans' answer:
fizzBuzz = [(x, f 3 "fizz" x ++ f 5 "buzz" x) | x <- [1..100]]
where f k s n | n `mod` k == 0 = s
| otherwise = ""
I think the reason why you feel like you are fighting the syntax is because you are mixing too many types.
Instead of trying to print:
[(1, ""), (2,""), (3,"Fizz")...]
Just think of printing strings:
["1","2","Fizz"...]
My attempt:
Prelude> let fizzBuzz x | x `mod` 15 == 0 = "FizzBuzz" | x `mod` 5 == 0 = "Buzz" | x `mod` 3 == 0 = "Fizz" | otherwise = show x
Prelude> [fizzBuzz x | x <-[1..100]]
["1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11","Fizz","13","14","FizzBuzz"...]
In order to convert an Int to String you use the:
show x
Just for studying
zipWith (\a b -> b a) (map show [1..100]) $ cycle [id,id,const "fizz",id,const "buzz",const "fizz",id,id,const "fizz",const "buzz",id,const "fizz",id,id,const "fizzbuzz"]
produces
["1","2","fizz","4","buzz","fizz","7","8","fizz","buzz","11","fizz","13","14","fizzbuzz","16","17","fizz","19","buzz","fizz","22","23","fizz","buzz","26","fizz","28","29","fizzbuzz","31","32","fizz","34","buzz","fizz","37","38","fizz","buzz","41","fizz","43","44","fizzbuzz","46","47","fizz","49","buzz","fizz","52","53","fizz","buzz","56","fizz","58","59","fizzbuzz","61","62","fizz","64","buzz","fizz","67","68","fizz","buzz","71","fizz","73","74","fizzbuzz","76","77","fizz","79","buzz","fizz","82","83","fizz","buzz","86","fizz","88","89","fizzbuzz","91","92","fizz","94","buzz","fizz","97","98","fizz","buzz"]
Writer monad may look nice (if you don't like concat):
fizzBuzz = [(x, execWriter $ when (x `mod` 3 == 0) (tell "fizz") >> when (x `mod` 5 == 0) (tell "buzz")) | x <- [1..100]]
It's not particularly succinct though.