Last active
December 14, 2015 23:09
-
-
Save fogus/5163546 to your computer and use it in GitHub Desktop.
How do I say this Haskell?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- THE SEARCH CONTINUES | |
data GenericThing = SpecificThing Char | |
| DifferentSpecificThing Double | |
| AnotherSpecificThing String | |
| YetAnotherDifferentSpecificThing Integer | |
foo :: [GenericThing] -> GenericThing | |
foo [] = return $ AnotherSpecificThing "" | |
foo [SpecificThing one] = -- do something | |
foo (SpecificThing c : cs) = -- do something else | |
foo badThings = -- throw if given any other kind of Thing | |
-- How can I express | |
-- - Do something for an array of one SpecificThing | |
-- - Do something else for an array of many SpecificSomethings | |
-- - Otherwise throw an error | |
-- The code above only checks the head of the lists, it does not type check the rest in the many case |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- My answer | |
data GenericThing = SpecificThing Char | |
| DifferentSpecificThing Double | |
| AnotherSpecificThing String | |
| YetAnotherDifferentSpecificThing Integer | |
extricate :: ThrowsError Char | |
extricate (SpecificThing c) = return c | |
extricate notChar = throwError $ FrobnicateError notChar | |
foo :: [GenericThing] -> GenericThing | |
foo [] = return $ AnotherSpecificThing "" | |
foo [SpecificThing one] = -- do something | |
foo things = mapM extricate things >>= return . AnotherSpecificThing |
foo :: [GenericThing] -> GenericThing
foo = bar $ map $ \st@(SpecificThing _) -> st -- will call error if there's a bad match
where bar [SpecificThing one] = -- do something
bar many = -- many specific things
Perhaps something like this?:
foo :: [GenericThing] -> GenericThing
foo xs = SpecificThing $ doThings [c | SpecificThing c <- xs]
doThings :: [Char] -> Char
doThings (x:xs) = -- do something
doThings [] = -- we didn't get any SpecificThings, error
-- there's probably a GHC extension to autogenerate this
isSpecificThing :: GenericThing -> Bool
isSpecificThing (SpecificThing _) = True
isSpecificThing _ = False
-- this is the easy case, of course
foo [SpecificThing one] = doSomething one
-- Haskell doesn't know at compile time whether an array contains only SpecificThings
-- so we need to dynamically test for it
foo xs | all xs isSpecificThing = doSomethingElse xs
| otherwise = error "Whatever"
-- Although "Good Haskell" doesn't really use error often.
-- Instead you'd use a Maybe or Either probably.
-- Of course, this is fundamentally kind of a confused question.
-- "Good Haskell" would have you design your types/structure in such a way
-- that you don't need to dynamically test if each thing is a SpecificThing
-- probably by making a GenericInterface typeclass
-- and then making each SpecificTypeOfThing its own type
-- rather than have them share a sum type
Q:
-- How can I express
-- - Do something for an array of one SpecificThing
-- - Do something else for an array of many SpecificSomethings
-- - Otherwise throw an error
A:
data GenericThing = SpecificThing Char
| DifferentSpecificThing Double
| YetAnotherDifferentSpecificThing Integer
deriving Show
-- showing the use of exceptions (error)
foo :: [GenericThing] -> GenericThing
foo a@(x:xs)
| specific x && null xs = oneSpecificThing x
| all specific a = lotsOfSpecificThings a
| otherwise = error "Not All SpecificThings"
where specific (SpecificThing _) = True
specific _ = False
oneSpecificThing = id -- or other impl
lotsOfSpecificThings = head -- or other impl
foo _ = error "Bad Input!?"
-- showing another way to do it by using Either
bar :: [GenericThing] -> Either String GenericThing
bar a@(x:xs)
| specific x && null xs = Right $ oneSpecificThing x
| all specific a = Right $ lotsOfSpecificThings a
| otherwise = Left "Not All SpecificThings"
where specific (SpecificThing _) = True
specific _ = False
oneSpecificThing = id -- or other impl
lotsOfSpecificThings = head -- or other impl
bar _ = Left "Bad Input!?"
-- showing another way to do it with Maybe
baz :: [GenericThing] -> Maybe GenericThing
baz a@(x:xs)
| specific x && null xs = Just $ oneSpecificThing x
| all specific a = Just $ lotsOfSpecificThings a
| otherwise = Nothing
where specific (SpecificThing _) = True
specific _ = False
oneSpecificThing = id -- or other impl
lotsOfSpecificThings = head -- or other impl
baz _ = Nothing
-- main so you can try it - use `runhaskell ./Gist.hs`
main :: IO ()
main = do
putStrLn . show $ foo [SpecificThing 'u']
putStrLn . show $ bar [SpecificThing 'a', SpecificThing 'b']
putStrLn . show $ baz [SpecificThing 'a', DifferentSpecificThing 2.0]
putStrLn . show $ bar [YetAnotherDifferentSpecificThing 5]
putStrLn . show $ foo [YetAnotherDifferentSpecificThing 5, DifferentSpecificThing 2.0]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
At the moment I have
foo things = -- do something else
, but that seems janky and fails with an inexhauted pattern thingy (I'm being less than technical here)