Wrong output of simple Haskell exercise solution - haskell

I am trying to solve this exercise:
You are given a sequence of N balls in 4 colors: red, green, yellow
and blue. The sequence is full of colors if and only if all of the
following conditions are true:
There are as many red balls as green balls.
There are as many yellow balls as blue balls.
Difference between the number of red balls and green balls in every prefix of the sequence is at most 1.
Difference between the number of yellow balls and blue balls in every prefix of the sequence is at most 1.
Your task is to write a program, which for a given sequence prints True if it is full of colors, otherwise it prints False.
My solution so far is:
module Main where
import Control.Monad
main = do
s <- readLn :: IO Int
elements <- replicateM s getLine
let result = map checkColours elements
mapM (putStrLn . show) result
checkColours :: String -> Bool
checkColours string = isFullOfColors 0 0 0 0 string
isFullOfColors :: Int -> Int -> Int -> Int -> String -> Bool
isFullOfColors red green yellow blue string
| (abs (red - green)) > 1 = False
| (abs (yellow - blue)) > 1 = False
| (string == []) = if (red /= yellow) || (green /= blue) then True else False
| (head string == 'R' ) = isFullOfColors (red + 1) green yellow blue (tail string)
| (head string == 'G' ) = isFullOfColors red (green + 1) yellow blue (tail string)
| (head string == 'Y' ) = isFullOfColors red green (yellow + 1) blue (tail string)
| (head string == 'B' ) = isFullOfColors red green yellow (blue + 1) (tail string)
But it fails on the input "RYBG", returning False instead of True.
What am I doing wrong?

Besides C. Quilley's comments, here is some general advice and a suggestion for structuring your function differently. The guard string == [] is better written as null string, since the built-in function null will make this decision with a single pattern match, rather than having to rely on the list of elements being comparable (which it only is when the elements of the list themselves are comparable). The pattern if ... then True else False can be shortened to ..., since this is already a boolean with the same value. Generally, try and use pattern matching!
I cannot see where you derive (red /= yellow) || (green /= blue) from. When does the number of red balls and yellow balls have constraints in common?
Instead of a String, you may want to create a data type that reflects balls:
data Ball = Red | Green | Yellow | Blue
deriving Eq
You may want them to be displayed just the same as before:
instance Show Ball where
show Red = "R"
show Green = "G"
show Yellow = "Y"
show Blue = "B"
And you may want to embed the helper function inside the main function:
isFullOfColors :: [Ball] -> Bool
isFullOfColors = go (0, 0, 0, 0)
where
go :: (Int, Int, Int, Int) -> [Ball] -> Bool
go (r,g,y,b) (Red:balls) = ...
go (r,g,y,b) (Green:balls) = ...
go (r,g,y,b) (Yellow:balls) = ...
go (r,g,y,b) (Blue:balls) = ...
go (r,g,y,b) [] = ...
As for hints on the logical part: These can be expressed as comparisons between r, g, y and b in combination with recursive calls to balls.

Related

Haskel how can I turn this list of string into a list of lists?

The string looks like this:
",w84,w41,w56,w170,w56,w41,w84,/,,w24,w40,w17,w40,w48,,/ ,,,w16,w16,w16,,,/,,,,,,,,/,,,,,,,,/,,,,,,,,/,,,b1,b1,b1,,,/ ,,b3,b130,b17,b130,b129,,/,b69,b146,b131,b170,b131,b146,b69,"
But it should look like this
[[Empty,Piece White 84,Piece White 41,Piece White 56,Piece White 170,Piece White 56,Piece White 41,Piece White 84,Empty],[Empty,Empty,Piece White 24,Piece White 40,Piece White 17,Piece White 40,Piece White 48,Empty,Empty],[Empty,Empty,Empty,Piece White 16,Piece White 16,Piece White 16,Empty,Empty,Empty],[Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty],[Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty],[Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty],[Empty,Empty,Empty,Piece Black 1,Piece Black 1,Piece Black 1,Empty,Empty,Empty],[Empty,Empty,Piece Black 3,Piece Black 130,Piece Black 17,Piece Black 130,Piece Black 129,Empty,Empty],[Empty,Piece Black 69,Piece Black 146,Piece Black 131,Piece Black 170,Piece Black 131,Piece Black 146,Piece Black 69,Empty]]
The list my code creates looks like this:
[["Empty,Piece White 84,Piece White 41,Piece White 56,Piece White 170,Piece White 56,Piece White 41,Piece White 84,Empty"],
["Empty,Empty,Piece White 24,Piece White 40,Piece White 17,Piece White 40,Piece White 48,Empty,Empty"],
["Empty,Empty,Empty,Piece White 16,Piece White 16,Piece White 16,Empty,Empty,Empty"],
["Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty"]
data Player = Black | White deriving Show
data Cell = Piece Player Int | Empty deriving Show
data Pos = Pos { col :: Char, row :: Int } deriving Show
type Board = [[Cell]]
I have these data types.
I am almost done with this task all I need is to get rid of the quotation marks.
This is my code so far:
buildBoard x = rec(help3(wop(helper (replaceO x))))
wop (x:xs) = splitOn "/" (x:xs)
help3 (x:xs) = map (\x -> [x])(x:xs)
rec (x:xs) = map(\x -> [recH(x)])(x:xs)
recH (x:xs) = checkComma(x)
helper (x:y:xs)
|x == ',' && y == ',' = x:'E':'m':'p':'t':'y':helper(y:xs)
|otherwise = x:helper (y:xs)
helper [] = []
helper [x] = [x]
checkComma (x:xs) = if head (x:xs) == ',' then checkComma('E':'m':'p':'t':'y':',':xs) else if last (x:xs) == ',' then reverse(turnAr(reverse(x:xs))) else (x:xs)
turnAr (x:xs) = 'y':'t':'p':'m':'E':',':xs
replaceO [] = []
replaceO (x:xs) =
if x == 'w'
then 'P':'i':'e':'c':'e':' ':'W':'h':'i':'t':'e':' ': replaceO xs
else if x == 'b'
then 'P':'i':'e':'c':'e':' ':'B':'l':'a':'c':'k':' ': replaceO xs
else if x == 'E'
then 'E':'m':'p':'t':'y':' ': replaceO xs
else x : replaceO xs
Just getting rid of the quotation marks is not something you can easily do.
I think you'll have to make some significant changes to your code. I'd recommend doing the splitOn "/" first and then further splitOn "," which yields a list of lists of strings where each of the strings represents a cell.
Then you can pretty easily write a function parseCell :: String -> Cell to parse those inner cells. This function will be a bit like your replaceO function but it should also handle all empty cells and actually parsing the integers (you can use the read function for that).

How to count number of times guard statement happens in recursion?

I'm new to haskell and I got stuck in a little program I tried to make. I want to count number of times my guard statement goes through in all recursion rounds and then return that as Int. For example if c1 is 'a', c2 is 'b', g is 2 and s is "aaabbb" then returned int would be 2, because my guard statement is true in 2 cases.
I tried to make variable x and then add x + 1 to it every time guard statement happens. That didn't work because I learnt that in Haskell variable you set is always static so for example setting x = 0 at start would set that x to 0 every recursion round.
Here's my code:
gaps :: (Char, Char) -> Int -> String -> Int
gaps (c1,c2) g (s:xs)
| c1 == s && c2 == (s:xs) !! g = --Count how many times this statement happens --
| otherwise = gaps (c1,c2) g xs
Just add 1 and call the function recursively
gaps :: (Char, Char) -> Int -> String -> Int
gaps _ _ [] = 0 -- base case
gaps (c1,c2) g (s:xs)
| c1 == s && c2 == (s:xs) !! g = 1 + gaps (c1,c2) g xs -- add one to final result
| otherwise = gaps (c1,c2) g xs
> gaps ('a','b') 2 "aaabbb"
2
> gaps ('a','b') 3 "aaaabbbb"
3
Be carefull when using !!. It isn't total and might fail if your input string has c1's values less than g positions before the end of the string
> gaps ('a','b') 3 "aaaababbb" -- doesn't fail
3
> gaps ('a','b') 3 "aaaabbabb" -- does fail!!!!
Off the back of questions on how to make this thing safer, I have made the following code snippet, borrowing from Ismor's answer.
-- a way to safely get the nth item from a list
get' :: [a] -> Int -> Maybe a
get' [] _ = Nothing
get' (x:xs) 0 = Just x
get' (x:xs) n
| n > 0 = get' xs (n-1)
| otherwise = Nothing
-- takes a Maybe value. if it's Nothing, return 0. if it's Just a value, compare
-- the value and a given param, if equal return 1, else 0
seeEqual:: (Num b, Eq a) => Maybe a -> a -> b
seeEqual Nothing _ = 0
seeEqual (Just a) b
| a==b = 1
| otherwise = 0
-- I have edited the first guard so that it checks c1 and s, then tries to calculate
-- whether c2 and the specific list item are equal, and then recurses as before
gaps :: (Char, Char) -> Int -> String -> Int
gaps _ _ [] = 0 -- base case
gaps (c1,c2) g (s:xs)
| c1 == s = (seeEqual (get' (s:xs) g) c2) + gaps (c1,c2) g xs -- add one to final result
| otherwise = gaps (c1,c2) g xs
I do not claim that this is perfect, but I do think this is safe and shouldn't throw any exceptions or raise any errors.
Prelude> gaps ('a','b') 3 "aaaababbb"
3
Prelude> gaps ('a','b') 3 "aaaabbabb"
2

Haskell. getting same neighbors

I'm the cs student who recently started to learn Haskell.
I tried my best to find the way to interpret in Haskell but I couldn't yet. I need help. Here's the explanation. There are three types of content.
type Coord = (Int, Int)
-- Type-definition of a Cell: it is just a coordinate and an optional
AgentType.
-- Note: the agent type is optional and is Nothing in case the cell is
empty.
type Cell = (Coord, Maybe AgentType)
-- data definition for the agent types
data AgentType
= Red -- ^ Red agent
| Green -- ^ Green agent
| Blue -- ^ Blue agent
deriving (Eq, Show) -- Needed to compare for equality, otherwise would need to implement by ourself
Each cell has either a content( can be red, green or blue) or empty. I'm trying to find the neighbours who have the same content from every side including diagonal ways which is 8 in total. If 40% of the cell neighbours are the same as the cell, return true.
-- Returns True if an agent on a given cell is happy or not
isHappy :: Double -- ^ The satisfaction factor
-> [Cell] -- ^ All cells
-> Cell -- ^ The cell with the agent
-> Bool -- ^ True in case the agent is happy, False otherwise
isHappy ratio cs c
| ratio < 0.4 = False
| otherwise = True
where
moore = [(x-1,y-1),(x-1,y),(x-1,y+1),(x,y+1),(x+1,y+1),(x+1,y),(x+1,y-1),(x,y-1)]
-- here is where I got stuck
I made a 'moore' list which contains all direction, but I'm not sure how to compare 'the Cell' to 'neighbours [Cell]'.
My thought is following in another programming language,
if (TheCell[X-1,Y] == TheCell)){
stack ++;
}
...
...
ratio = stack / len(8);
I've been searching how to interpreted in Haskell but couldn't find it yet. Maybe my thinking process is wrong. Please help me in any way
data Cell = Cell Coord (Maybe AgentType)
inBounds :: Coord -> Bool
inBounds (x,y) = 0 <= x && x <= fst worldSize
&& 0 <= y && y <= snd worldSize
isHappy cs (Cell (x,y) a) = ratioSameNeighbours >= 0.4
where neighbourCoords = filter inBounds [(x-1,y-1),(x-1,y),(x-1,y+1),(x,y+1),(x+1,y+1),(x+1,y),(x+1,y-1),(x,y-1)]
sameNeighbours = filter ((\(Cell p ma) -> p `elem` neighbourCoords && ma == a) cs
ratioSameNeighbours = fromIntegral (length sameNeighbours) / fromIntegral (length neighbours)
What you've said is still a bit underspecified, (eg. can an empty cell ever be happy?) but this is a start. If the input cell array is supposed to be 2D (rather than a "sparse" representation ie. 1D list of only the non-empty cells) then ratio has to be a bit different.

How to check if coords(x,y) are valid on a board in Haskell

I have a function
isValid :: CoOrd -> Bool
Where CoOrd is a tuple pair (x,y)
The boards size is ['a'..'h'] ['1'..'8'] so I want to check if the given CoOrds are valid for this board (CoOrds x < ['a'..'h'], CoOrds y ['1'..'8'])
I'm fine with the logic of this question, its just the syntax as I'm new to haskell, so I'm looking for something like this
if (CoOrd(x _) == ['a'..'h'])
if (CoOrd(_ y) == ['1'..'8'])
return True
else return False
The basic approach is to use direct comparisons:
isValid :: CoOrd -> Bool
isValid (x,y) = x >= 'a' && x <= 'h' && y >= '1' && y <= '8'
A more advanced alternative is to exploit Data.Ix.inRange:
import Data.Ix
isValid :: CoOrd -> Bool
isValid = inRange (('a','1'),('h','8'))
You can also use elem, as others pointed out, but elem will scan the whole list and perform pointwise comparisons (8+8 comparisons, in the worst case), while the methods above will only do four comparisons.
Finally, a few comments on your original code:
Don't use return in Haskell unless you are writing monadic code
Don't use if condition then True else False -- that's noise, and it is equivalent to conditions. Consider using boolean operators instead, which is often simpler.
Why not make some new types for your X and Y coordinates so the type checker gives you a static guarantee that any CoOrd value is correct?
For example, I think you have type CoOrd = (Char,Int). Instead try:
data XCo = A | B | C | D | E | F | G | H deriving (Eq,Ord,Show,Enum)
data YCo = Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 | Y8 deriving (Eq,Ord,Enum)
instance Show YCo where
show y = show (fromEnum y + 1)
type CoOrd = (XCo,YCo)
And now anywhere you were using character literals like 'a', 'b' etc you use A, B etc. Same with the numbers and the Y axis - 1 becomes Y1 etc.
isValid (x,y) = x `elem` ['a'..'h'] && y `elem` ['1'..'8']
In addition to the other answers instead of using tuples you may define a new type, for example ChessBoard.
Since you are in need of checking the validity of the entered position it might be wise to make it Maybe ChessBoard type as well.
Accordingly you may come up with something like
module ChessBoard (ChessBoard, chessBoard) where
data ChessBoard = CB Char Int deriving (Eq, Ord, Show)
chessBoard :: Char -> Int -> Maybe ChessBoard
chessBoard c n | elem c ['a'..'h'] && elem n [1..8] = Just (CB c n)
| otherwise = Nothing
Here as you may notice we are not exporting the data constructor CB Char Int so the only way to create your chess board position data is through the chessBoard function and there will be no illegal board positions.
I mean;
*Main> chessBoard 'a' 3
Just (CB 'a' 3)
*Main> chessBoard 'h' 9
Nothing
*Main> let pos = Just (CB 'a' 11) -- trying to assign an illegal position directly
<interactive>:259:17: error:
Data constructor not in scope: CB :: Char -> Integer -> a

Pattern match data types and their nested name in Haskell

I have:
data Color = Blue | GreenĀ | Red | White | Yellow deriving (Eq,Ord)
And then
data Term = Color | ...
data Bag = Bag {
color :: Color
...
}
Now I want to be able to pattern match to make sure that the term given is a Color and if so check it's "value" (Blue/Green...). Something like this:
func :: Term -> Bag -> Bool
func (c :: Color) bag = (color bag) == c
But (c :: Color) does not seem to work.
data Color = Blue | Green | Red | White | Yellow deriving (Eq,Ord)
data Term = Color Color | Trash
data Bag = Bag {
color :: Color
}
func (Color x) bag = (color bag) == x
-- With the above, a call of func Trash something will fail.
-- (unexhastive pattern match). You can add
func Trash bag = False
-- or
func _ _ = False
-- and it will work all time.
Here is a somewhat wordier account, no different in content from sdcvvc's, I think.
data Color = Blue | Green | Red | White | Yellow deriving (Eq,Ord,Show)
data Size = Small | Medium | Large deriving (Eq, Ord, Show)
data Term = TColor Color | TSize Size | Trash deriving Show
data Bag = Bag {color :: Color , size :: Size} deriving Show
Notice that unlike sdcvvc I used "TColor Color". It's no different since the typechecker can tell that one is an already established type the other is a new constructor of a new type, even if they're spelled the same. It's just little less confusing. Something like "Color Color" would not be so uncommon these days, but in a older book like Bird's "Intro to FP with Haskell," he wouldn't do this sort of thing. It's a bit like the Haskeller's vogue for things like "\file -> readFile file" which has its advantages, but is potentially confusing and it seems pretty recent; formerly it would have been just \x -> readFile x or something.
theMrsThatcher :: Bag
theMrsThatcher = Bag Blue Large
theMrsRobinson :: Bag
theMrsRobinson = Bag {color = Green, size = Small} -- to use the other syntax
colorCheck :: Term -> Bag -> Bool
colorCheck (TColor c) b = True
colorCheck (TSize s) b = False -- as sdcvvc says, this and
colorCheck Trash b = False -- the next clause can be replaced by
-- colorCheck _ _ = False
Note also that in colorCheck the bag is irrelevant. It isn't clear from what you say why you need the intermediate type Term.
colorTest :: Color -> Bag -> Bool
colorTest c b = color b == c
colorCheckTest :: Term -> Bag -> Bool
colorCheckTest (TColor c) b = color b == c
colorCheckTest (TSize s) b = False -- as above, the last clauses are
colorCheckTest Trash b = False -- wordier than need be since any
-- but the first pattern is a loser.
Results:
*Main> colorCheck (TColor Blue) theMrsRobinson
True
*Main> colorCheck (TColor Blue) theMrsThatcher
True
*Main> colorCheckTest (TColor Blue) theMrsRobinson
False
*Main> colorCheckTest (TColor Blue) theMrsThatcher
True
*Main> colorTest Blue theMrsThatcher
True
*Main> colorTest Blue theMrsRobinson
False

Resources