I need to write a program which decodes a list of four values, which can be either I or O into a list of [Either Bool Bool]. I know I have to use maybe, but I simply cannot wrap my head around it. Right now I am totally desperate because I simply cannot solve this problem.
An example input and output might look like this: [I,O,O,I] => [Left True, Right False]
Here is the current code I have:
module Blueprint where
import Prelude
import Data.Maybe
data Bit = O | I deriving (Eq, Show)
encode :: [Either Bool Bool] -> [Bit]
encode [] = []
encode l = case head l of
Left False -> [I, I] ++ encode (tail l)
Left True -> [I, O] ++ encode (tail l)
Right False -> [O, I] ++ encode (tail l)
Right True -> [O, O] ++ encode (tail l)
decode :: [Bit] -> Maybe [Either Bool Bool]
decode [] = Nothing
decode [x] = Nothing
decode l = if isNothing (decode (tail (tail l)))
then Nothing
else case head l of
I -> if l!!1 == I
then [Left False] ++ decode (tail (tail l))
else [Left True] ++ decode (tail (tail l))
O -> if l!!1 == I
then [Right False] ++ decode (tail (tail l))
else [Right True] ++ decode (tail (tail l))
and these are the errors I get:
Prelude> :load serialise
[1 of 1] Compiling Blueprint ( serialise.hs, interpreted )
serialise.hs:22:16:
Couldn't match expected type `Maybe [Either Bool Bool]'
with actual type `[Either Bool b0]'
In the expression: [Left False] ++ decode (tail (tail l))
In the expression:
if l !! 1 == I then
[Left False] ++ decode (tail (tail l))
else
[Left True] ++ decode (tail (tail l))
In a case alternative:
I -> if l !! 1 == I then
[Left False] ++ decode (tail (tail l))
else
[Left True] ++ decode (tail (tail l))
serialise.hs:22:33:
Couldn't match expected type `[Either Bool b0]'
with actual type `Maybe [Either Bool Bool]'
In the second argument of `(++)', namely `decode (tail (tail l))'
In the expression: [Left False] ++ decode (tail (tail l))
serialise.hs:23:16:
Couldn't match expected type `Maybe [Either Bool Bool]'
with actual type `[Either Bool b1]'
In the expression: [Left True] ++ decode (tail (tail l))
In the expression:
if l !! 1 == I then
[Left False] ++ decode (tail (tail l))
else
[Left True] ++ decode (tail (tail l))
In a case alternative:
I -> if l !! 1 == I then
[Left False] ++ decode (tail (tail l))
else
[Left True] ++ decode (tail (tail l))
serialise.hs:23:32:
Couldn't match expected type `[Either Bool b1]'
with actual type `Maybe [Either Bool Bool]'
In the second argument of `(++)', namely `decode (tail (tail l))'
In the expression: [Left True] ++ decode (tail (tail l))
serialise.hs:25:16:
Couldn't match expected type `Maybe [Either Bool Bool]'
with actual type `[Either a0 Bool]'
In the expression: [Right False] ++ decode (tail (tail l))
In the expression:
if l !! 1 == I then
[Right False] ++ decode (tail (tail l))
else
[Right True] ++ decode (tail (tail l))
In a case alternative:
O -> if l !! 1 == I then
[Right False] ++ decode (tail (tail l))
else
[Right True] ++ decode (tail (tail l))
serialise.hs:25:34:
Couldn't match expected type `[Either a0 Bool]'
with actual type `Maybe [Either Bool Bool]'
In the second argument of `(++)', namely `decode (tail (tail l))'
In the expression: [Right False] ++ decode (tail (tail l))
serialise.hs:26:16:
Couldn't match expected type `Maybe [Either Bool Bool]'
with actual type `[Either a1 Bool]'
In the expression: [Right True] ++ decode (tail (tail l))
In the expression:
if l !! 1 == I then
[Right False] ++ decode (tail (tail l))
else
[Right True] ++ decode (tail (tail l))
In a case alternative:
O -> if l !! 1 == I then
[Right False] ++ decode (tail (tail l))
else
[Right True] ++ decode (tail (tail l))
serialise.hs:26:32:
Couldn't match expected type `[Either a1 Bool]'
with actual type `Maybe [Either Bool Bool]'
In the second argument of `(++)', namely `decode (tail (tail l))'
In the expression: [Right True] ++ decode (tail (tail l))
Failed, modules loaded: none.
Right now anything that helps me solve this problem is welcome. I have tried this for the better part of the day and I simply can't solve it.
You need to put a Just before your case statement to convert those values to Maybe [Either Bool Bool] instead of just [Either Bool Bool]:
decode :: [Bit] -> Maybe [Either Bool Bool]
decode [] = Nothing
decode [x] = Nothing
decode l = if isNothing (decode (tail (tail l)))
then Nothing
else Just $ case head l of
I -> if l!!1 == I
then [Left False] ++ decode (tail (tail l))
else [Left True] ++ decode (tail (tail l))
O -> if l!!1 == I
then [Right False] ++ decode (tail (tail l))
else [Right True] ++ decode (tail (tail l))
But this won't solve all of it. You also have decode embedded in that computation, and its type is Maybe [Either Bool Bool], but to use ++ you need just the [Either Bool Bool] as ++ only works with lists. This is where the Maybe monad comes in handy:
decode [] = Nothing
decode [x] = Nothing
decode (x:y:rest) = do
end <- decode rest
let this = case (x, y) of
(I, I) -> Left False
(I, O) -> Left True
(O, I) -> Right False
(O, O) -> Right True
return (this : end)
The case statement here is really just a different way of writing your case/nested-ifs. I also used pattern matching to avoid all the uses of head, !!, and tail since those functions should usually be avoided (they call error instead of doing proper error handling using Maybe). The <- syntax for Maybe will exit the computation early if Nothing is returned, so end <- decode rest is the same as saying if isNothing (decode rest) then Nothing else <continue>. Then, instead of building the entire result in each branch of the case/ifs, just compute the single result from x and y, then build the result list at the end.
Related
so I have this code fragment: where exponent = read (tail (dropWhile (/= '^') (head xs))) :: Int but there is a possibility of the list inside tail being empty, so that would mean there would be an error looking for a tail inside an empty list. Is there a way to do something like: if error: exponent = 1 ?
Here is the full function if it helps in any way :)
internalRepresentation :: [String] -> [(Int,Char ,Int)]
internalRepresentation xs
|null xs = []
|all isDigit (head xs) = (read (head xs), ' ', 0) : internalRepresentation (tail xs)
|head (head xs) == '-' = (-read (takeWhile isDigit (pos_mon)) :: Int, head (dropWhile isDigit (pos_mon)), exponent) : internalRepresentation (drop 1 xs)
|otherwise = (read (takeWhile isDigit (head xs)) :: Int, head (dropWhile isDigit (head xs)), exponent) : internalRepresentation (drop 1 xs)
where pos_mon = tail (head xs)
exponent = read (tail (dropWhile (/= '^') (head xs))) :: Int
Thanks for your time!
The functions read, head, and tail are partial which means that they can fail with an error as you have experienced. That is why many people avoid those functions. Personally, I would write it like this:
import Text.Read (readMaybe)
internalRepresentation' :: String -> (Int, Char, Int)
internalRepresentation' xs =
case reads xs of
[(n, "")] -> (n, ' ', 0)
[(n, x:xs')] ->
case readMaybe (drop 1 (dropWhile (/= '^') (x:xs'))) of
Just e -> (n, x, e)
Nothing -> error "Malformed exponent"
_ -> error "Malformed internal representation"
internalRepresentation :: [String] -> [(Int, Char, Int)]
internalRepresentation xs = map internalRepresentation' xs
You can probably avoid that ugly drop 1 (dropWhile (/= '^') (x:xs')) too if you constrain your input a bit more. But I'm not completely sure what this function is actually supposed to do, so I can't help much more.
For example, if you only want to parse strings that look exactly like 123^456 (without other characters in between), then you can write it like this:
internalRepresentation' xs =
case reads xs of
[(n, "")] -> (n, ' ', 0)
[(n, '^':xs')] ->
case readMaybe xs' of
Just e -> (n, '^', e)
Nothing -> error "Malformed exponent"
_ -> error "Malformed internal representation"
Im getting parse error on my if then else statement and I dont understand why. I have checked the functions, and as far as I can tell all of them are getting the arguments they need, so I dont understand why this is happening. Im very new to haskell so help in understanding this would be deeply appreciated.
replace :: [(Int,Int)] -> String -> String
replace xs ys = if translate (manipulator (fst (convert xs)) (snd (convert xs)) ys) /= ""
then take (fst (convert xs)) ys ++ (manipulator (fst (convert xs)) (snd (convert xs)) ys) ++ drop (snd (convert xs)) ys
else take (fst (convert xs)) ys ++ stjerner (snd (convert xs) - fst (convert xs)) ++ drop (snd (convert (xs)) ys
--get parse error here, see picture.
stjerner :: Int -> String
stjerner 0 = ""
stjerner int | int > 0 = "*" ++ stjerner (int -1)
manipulator:: Int -> Int -> String -> String
manipulator low high xs = take high (drop low xs)
convert :: [a] -> a
convert [a] = a
picture of parse error here
The last expression in you else clause --- drop (snd (convert (xs)) ys -- is misparenthesized. You've got 3 open parens but only 2 close parens. I think you meant drop (snd (convert xs)) ys.
I just started learning Haskell, and I intended to code a function that would return to last list 2.
lastButOne x = if ((==) (length x) 2)
then (head x)
else (tail x)
this is error:
‧ Occurs check: cannot construct the infinite type: a ~ [a]
‧ In the expression: (tail x)
In the expression:
if ((==) (length x) 2) then (head x) else (tail x)
In an equation for ‘lastButOne’:
lastButOne x = if ((==) (length x) 2) then (head x) else (tail x)
‧ Relevant bindings include
x :: [a] (bound at D:\\tool\8.6.3\test\lBoErr.hs:1:12)
lastButOne :: [a] -> a (bound at D:\\tool\8.6.3\test\lBoErr.hs:1:1)
|
3 | else (tail x)
| ^^^^^^
I do not understand where my code is wrong and what the error meant.
lastButOne has intended type [a] -> a, but with tail x you are trying to return a value of type [a]. The error message results from the type checker's attempt to find a type which unifies with both a and [a], in an attempt to make sense of a function that returns one or the other depending on which branch is taken.
What you want to do is recurse on the tail of the list:
lastButOne x = if length x == 2
then head x
else lastButOne (tail x)
This is more naturally written using pattern matching, though.
lastButOne [x,_] = x -- lists of length exactly 2
lastButOne (_:xs) = lastButOne xs -- All other non-empty lists
Note lastButOne simply is not defined for empty or singleton lists, and will produce a run-time error if called on such. You can fix that by altering the return to Maybe a:
lastButOne :: [a] -> Maybe a
lastButOne [x,_] = Just x
lastButOne (_:xs) = lastButOne xs
lastButOne _ = Nothing
I was solving 10th problem from 99 problems in Haskell.
My solution was
-- Problem 10
encode:: String -> [(Int, Char)]
encode [] = []
encode (x:xs) = (length $ x : takeWhile (==x) xs, x) : encode $ dropWhile (==x) xs
The error that I got was
Prelude> :l 10-20.hs
[1 of 1] Compiling Main ( 10-20.hs, interpreted )
10-20.hs:4:17:
Couldn't match expected type `[Char] -> [(Int, Char)]'
with actual type `[(Int, Char)]'
The first argument of ($) takes one argument,
but its type `[(Int, Char)]' has none
In the expression:
(length $ x : takeWhile (== x) xs, x) : encode
$ dropWhile (== x) xs
In an equation for `encode':
encode (x : xs)
= (length $ x : takeWhile (== x) xs, x) : encode
$ dropWhile (== x) xs
10-20.hs:4:56:
Couldn't match expected type `[(Int, Char)]'
with actual type `String -> [(Int, Char)]'
In the second argument of `(:)', namely `encode'
In the expression: (length $ x : takeWhile (== x) xs, x) : encode
In the expression:
(length $ x : takeWhile (== x) xs, x) : encode
$ dropWhile (== x) xs
Failed, modules loaded: none.
Once I changed the code to
-- Problem 10
encode:: String -> [(Int, Char)]
encode [] = []
encode (x:xs) = (length $ x : takeWhile (==x) xs, x) : encode (dropWhile (==x) xs)
It compiles and run fine. Notice I just changed encode $ dropWhile (==x) xs to encode (dropWhile (==x) xs)
I have two questions here
How do I infer the change that I did (removing the $ application) from the GHCi error shown? I am unable to decipher this from the error thrown
Why does removing the $ work here?
($) performs function application with very low precedence, so
(length $ x : takeWhile (==x) xs, x) : encode $ dropWhile (==x) xs
is equivalent to
((length $ x : takeWhile (==x) xs, x) : encode) (dropWhile (==x) xs)
Which is ill-typed for two reasons. Firstly,
((length $ x : takeWhile (==x) xs, x) : encode)
would be a list built with the outermost (:), and not a function, and so it cannot be applied (thus the first error about the "first argument of ($)" which should take one argument). Secondly, encode is a String -> [(Int, Char)] function, and so it can't be the second argument of the outermost (:) (which should be a [(Int, Char)] given the type of the first argument, thus the second error).
explandDol :: String -> String -> [String] -> IO String
explandDol conclusion operators atoms =
let (ys,zs) = splitAt (head (take 1 replacement)) conclusion in ys ++ getConclusion operators atoms ++ (tail zs)
where replacement = elemIndices '$' conclusion
getConclusion :: String -> [String] -> IO String
getConclusion operators atoms =
runRVar (choice [atom1 ++ " " ++ [operator] ++ " " ++ atom2 | atom1 <- atoms, atom2 <- atoms, operator <- operators,checkAtoms atom1 atom2]) StdRandom
Is there a good way to fix this? I am getting this error:
/home/joe/Documents/haskell/LAG/main/main.hs: line 73, column 69:
Couldn't match expected type `IO String' with actual type `[Char]'
In the expression: ys ++ getConclusion operators atoms ++ (tail zs)
In the expression:
let (ys, zs) = splitAt (head (take 1 replacement)) conclusion
in ys ++ getConclusion operators atoms ++ (tail zs)
In an equation for `explandDol':
explandDol conclusion operators atoms
= let (ys, zs) = splitAt (head (take 1 replacement)) conclusion
in ys ++ getConclusion operators atoms ++ (tail zs)
where
replacement = elemIndices '$' conclusion
/home/joe/Documents/haskell/LAG/main/main.hs: line 73, column 75:
Couldn't match expected type `[Char]' with actual type `IO String'
In the return type of a call of `getConclusion'
In the first argument of `(++)', namely
`getConclusion operators atoms'
In the second argument of `(++)', namely
`getConclusion operators atoms ++ (tail zs)'
/home/joe/Documents/haskell/LAG/main/main.hs: line 73, column 75:
Warning: Redundant bracket
Found:
getConclusion operators atoms ++ (tail zs)
Why not:
getConclusion operators atoms ++ tail zs
Because value returned by getConclusion is IO String you cannot simply use it with functions operating on unwrapped values. Either first unwrap value using x <- getConclusion operators atom or if you want function composition use fmap.