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.
Related
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
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
Compiler warns the function "insert" is non-exhaustive in the following code:
data Set a = Empty | Set a (Set a) (Set a) deriving (Eq, Show)
insert :: (Ord a) => a -> Set a -> Set a
insert x Empty = Set x Empty Empty
insert x (Set v l r)
| x <= v = Set v (insert x l) r
| v < x = Set v l (insert x r)
-- | otherwise = Set x Empty Empty
main :: IO ()
main = do
let x = insert (5::Int) Empty
print x
GHC reports this
test.hs:4:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘insert’: Patterns not matched: _ (Set _ _ _)
If I uncomment the last line (it's commented out now) in the function, GHC does not report any warning. So I guess GHC thinks the guards are non-exhaustive. But why? If x and v are instances of Ord, then I guess
(x <= v) and (v < x) are all the possible outcomes of comparison?
What if I define this instance:
newtype Fuzzy = Fuzzy Double
instance Eq Fuzzy where
Fuzzy a == Fuzzy b = abs (a-b) < 0.1
instance Ord Fuzzy where
Fuzzy a < Fuzzy b = a < b-0.1
Fuzzy a <= Fuzzy b = a <= b
Then for e.g. v = Fuzzy 0, x = Fuzzy 0.1, you have (x <= v) = (0.1 <= 0) which is false, but (v < x) = (0 < 0) which is also false. Hence both of your guards will fail.
This isn't so hypothetical, in fact Double itself already has such behaviour in degenerate values:
Prelude> sqrt (-1) < 0
False
Prelude> 0 <= sqrt (-1)
False
Now, it's very debatable whether these are really good, even well-formed Ord instances, but at any rate the compiler can't guarantee something like that won't happen. Hence it also can't make the assumption that not (x <= v) implies v < x, so what should happen if neither is fulfilled?
The usual thing to do if you assume all Ord instances you received are docile is to just make the second clause already catch-all:
insert x (Set v l r)
| x <= v = Set v (insert x l) r
| otherwise = Set v l (insert x r)
However, depending on your philosophy, your original code might actually be better. With the catch-all in the second, you just defer the weirdness if someone hands you NaN values. This makes it all the more difficult to understand what's going on.
If tend to deliberately not complete patterns with “impossible cases” in experimental code: this way I'll at least always get a clear runtime error telling me at which point in the code things go awry. Once the code essentially works and you want to make it production-ready, you can then toss in -Wall and learn about all spots where you'd better add some explicit handling of pathological behaviour like the one I mentioned.
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.
i have given two points.
Now of i need to check if those points are identical, so i do:
type datatypePoint = (Float,Float)
anyLine :: datatypePoint -> datatypePoint -> datatypeLine
anyLine a b = [[fst a, fst b] , [snd a, snd b]]
| (fst a == fst b) && (snd a == snd b) = error "Identical"
| otherwise = error "Not identical"
But i get error:
unexpected |
anybody could tell me why? What am i doing wrong?
You have a few errors here, first off, all types start with upper case letters in Haskell
type Point = (Float,Float)
anyLine :: Point -> Point -> Point
Next, pattern matching happens before the = sign.
anyLine (a1, a2) (b1, b2)
| a1 == b1 && a2 == b2 = error "Identical"
| otherwise = error "Not identical"
And with guards we omit the equality sign.
This could also just be
anyLine a b
| a == b = ...
| otherwise = ...
I think it's well worth the time to read a good Haskell tutorial to learn some of the basic concepts you're missing, I personally favor Learn You A Haskell.
You can specify a result or define cases; you can't do both at the same time.
anyLine :: datatypePoint -> datatypePoint -> datatypeLine
anyLine a b
| (fst a == fst b) && (snd a == snd b) = error "Identical"
| otherwise = error "Not identical"
Other folks have already answered the question, but I wanted to point out that this would be even simpler if you used "newtype" and "deriving"
newtype Point a = Point (a, a) deriving (Eq)
anyLine a b
| a == b = ....
| otherwise = ....
It also doesn't hurt to keep the type a generic, so now this will work for "Point"s of Floats, Ints, etc.