I have this code:
module BalancedTwoDozenMultDrill where
import BalancedTwoDozenLib
myRandoms :: Int -> IO [Int]
myRandoms n = let x = 24^n `div` 2 in randomRs (-x,x) <$> getStdGen
drill :: [Int] -> IO ()
drill (x:y:rs) = do
putStr $ showInt x ++ " × " ++ showInt y ++ " = "
a <- getLine
case a of
"" -> return ()
showInt (x * y) -> do -- <= here
putStrLn "Correct"
drill rs
_ -> do
putStrLn $ "Wrong; " ++ showInt (x * y)
drill rs
main :: IO [Int]
main = drill =<< myRandoms =<< readLn
and get error:
BalancedTwoDozenMultDrill.hs:11:18: Parse error in pattern: x * y
However, replacing part of the case statement with:
-- ...stuff
let i = showInt (x * y)
case a of
"" -> return ()
i -> do
-- stuff...
Makes it parse (it goes to “not in scope” errors, which I can fix). The only reason I see for the first fragment being wrong is that there is function application going on. Is it true that I can't use ordinary function application for the alternatives in a case statement?
When you have a pattern in a case statement, it has to follow the same rules as that in pattern matching on function arguments. Only literals, constructors, and the wildcard _ can be matched on, not function applications. Instead, you could do something more like
a <- getLine
let xyStr = showInt (x * y) -- Avoid recomputation with a let binding
when (not $ null a) $ do
if a == xyStr
then do
putStrLn "Correct"
drill rs
else do
putStrLn $ "Wrong; " ++ xyStr
drill rs
You'll need to import when from Control.Monad, though.
The reason why you have to follow the same rules in case statements as in pattern matching in function definitions is because the compiler actually converts something like
head :: [a] -> a
head (x:xs) = x
head _ = error "Prelude.head: empty list"
Into
head :: [a] -> a
head list = case list of
(x:xs) -> x
_ -> error "Prelude.head: empty list"
The only reason we have the former version is convenience, it often makes for prettier looking code.
This link should be able to give you a more thorough explanation as to what is and isn't valid pattern matching constructs.
The other problem you had was trying to replace showInt (x * y) with i where let i = showInt (x * y). When you do this, you first bind the value showInt (x * y) to the name i, then in your case statement you have the patterns
"" -> ...
i -> ...
_ -> ...
So now your pattern is i, and it will act like a catch-all pattern after "". This rebinds the name i for the scope of that case statement.
A good rule to keep in mind is that you can't pattern match against a value obtained at run time, you have to check with equality or other comparison operations.
Although an answer already accepted I'd just mention there is a bit tricky way how use a boolean expressions in a case expression - by using guards:
case () of
_
| a == "" -> return ()
| showInt (x * y) -> do -- <= here
putStrLn "Correct"
drill rs
| otherwise -> do
putStrLn $ "Wrong; " ++ showInt (x * y)
drill rs
Related
Why is this function allowed:
-- function 1
myfunc :: String
myfunc = do
x <- (return True)
show x
and this is not:
-- function 2
myfunc :: String
myfunc = do
x <- getLine
show x
The compile error:
Couldn't match type `[]' with `IO'
Expected type: IO Char
Actual type: String
I get why function 2 shouldn't work, but why then thus function 1 work?
and why does this then work:
-- function 3
myfunc = do
x <- getLine
return (show x)
I get that it returns IO String then, but why is function 1 also not forced to do this?
In function1 the do block in myfunc is working in the list monad, because String is really just [Char]. In there, return True just creates [True]. When you do x <- return True that "extracts" True out of [True] and binds it to x. The next line show x converts True into a String "True". which being the return value the compiler value expects to see, ends up working fine.
Meanwhile in function2, the do block in myfunc is also working on the list monad (for the same reason, String being really [Char]) but calls on getLine which is only available in the IO monad. So unsurprisingly, this fails.
-- EDIT 1
OP has added a function3
-- function 3
myfunc :: String
myfunc = do
x <- getLine
return (show x)
No this should not work for the same reason function2 fails.
-- EDIT 2
OP has updated function3 to fix a copy paste error.
-- function 3
myfunc = do
x <- getLine
return (show x)
This is mentioned in the comments, but for clarity sake, this works because, when the type information is unspecified, GHC makes it best inference and after seeing getLine, it figures it’s IO String which does provide getLine.
Note - I wrote this answer with as casual a tone as I could manage without being wrong with the intention of making it approachable to a beginner level.
do blocks work in the context of an arbitrary Monad. The Monad, in this case, is []. The Monad instance for lists is based on list comprehensions:
instance Monad [] where
return x = [x]
xs >>= f = [y | x <- xs, y <- f x]
You can desugar the do notation thus:
myfunc :: String
myfunc = do
x <- (return True)
show x
-- ==>
myfunc = [y | x <- return True, y <- show x]
-- ==>
myfunc = [y | x <- [True], y <- show x]
In a list comprehension, x <- [True] is really just the same as let x = True, because you're only drawing one element from the list. So
myfunc = [y | y <- show True]
Of course, "the list of all y such that y is in show True" is just show True.
The two functions readMay and readMaybe have the same signature Read a => String -> Maybe a.
Is there any difference between them? If so, what are they? Which of the two function should be preferred?
There is no difference. Here's how readMay's defined:
-- | This function provides a more precise error message than 'readEither' from 'base'.
readEitherSafe :: Read a => String -> Either String a
readEitherSafe s = case [x | (x,t) <- reads s, ("","") <- lex t] of
[x] -> Right x
[] -> Left $ "no parse on " ++ prefix
_ -> Left $ "ambiguous parse on " ++ prefix
where
maxLength = 15
prefix = '\"' : a ++ if length s <= maxLength then b ++ "\"" else "...\""
where (a,b) = splitAt (maxLength - 3) s
readMay :: Read a => String -> Maybe a
readMay = eitherToMaybe . readEitherSafe
And here is readMaybe:
-- | Parse a string using the 'Read' instance.
-- Succeeds if there is exactly one valid result.
-- A 'Left' value indicates a parse error.
--
-- #since 4.6.0.0
readEither :: Read a => String -> Either String a
readEither s =
case [ x | (x,"") <- readPrec_to_S read' minPrec s ] of
[x] -> Right x
[] -> Left "Prelude.read: no parse"
_ -> Left "Prelude.read: ambiguous parse"
where
read' =
do x <- readPrec
lift P.skipSpaces
return x
-- | Parse a string using the 'Read' instance.
-- Succeeds if there is exactly one valid result.
--
-- #since 4.6.0.0
readMaybe :: Read a => String -> Maybe a
readMaybe s = case readEither s of
Left _ -> Nothing
Right a -> Just a
They differ in the intermediate error message (readEitherSafe shows the input), but the result will be same.
readMay from Safe predates readMaybe from Text.Read. Unless you're on a base version less than 4.6.0.0, use readMaybe from Text.Read as it does not need another package.
I want to lazily read user input and do something with it line by line. But if user ends a line with , (comma) followed by any number of spaces (including zero), I want give him opportunity to finish his input on the next line.
And here is what I've got:
import System.IO
import Data.Char
chop :: String -> [String]
chop = f . map (++ "\n") . lines
where f [] = []
f [x] = [x]
f (x : y : xs) = if (p . tr) x
then f ((x ++ y) : xs)
else x : f (y : xs)
p x = (not . null) x && ((== ',') . last) x
tr xs | all isSpace xs = ""
tr (x : xs) = x :tr xs
main :: IO ()
main =
do putStrLn "Welcome to hell, version 0.1.3!"
putPrompt
mapM_ process . takeWhile (/= "quit\n") . chop =<< getContents
where process str = putStr str >> putPrompt
putPrompt = putStr ">>> " >> hFlush stdout
Sorry, it doesn't work at all. Bloody mess.
P.S. I want to preserve \n characters on end of every chunk. Currently I add them manually with map (++ "\n") after lines.
How about changing the type of chop a little:
readMultiLine :: IO [String]
readMultiLine = do
ln <- getLine
if (endswith (rstrip ln) ",") then
liftM (ln:) readMultiLine
else
return [ln]
Now you know that if the last list is not empty, then the user didn't finish typing (the last input ended with ',').
Of course, either import Data.String.Utils, or write your own. Could be as simple as:
endswith xs ys = (length xs >= length ys)
&& (and $ zipWith (==) (reverse xs) (reverse ys))
rstrip = reverse . dropWhile isSpace . reverse
But I missed the point at first. Here's the actual thing.
unfoldM :: (Monad m) => (a -> Maybe (m b, m a)) -> a -> m [b]
unfoldM f z = case f z of
Nothing -> return []
Just (x, y) -> liftM2 (:) x $ y >>= unfoldM f
main = unfoldM (\x -> if (x == ["quit"]) then Nothing
else Just (print x, readMultiLine)) =<< readMultiLine
The reason is, you need to be able to insert the "action" to be done on input between reading one multi-line input and the next. Here print x is the action inserted between two readMultiLine
Since you have questions about getContents, let me add. Even though getContents provides a lazy String, its effectful changes to the world are ordered with the subsequent effects of processing the list. But the processing of the list attempts to insert effects between effects of reading particular list items. To do that, you need a function that exposes the chain of effects, so you can insert your own effects between them.
You can do this using pipes, preserving the laziness of the user's input
import Data.Char (isSpace)
import Pipes
import qualified Pipes.Prelude as Pipes
endsWithComma :: String -> Bool
endsWithComma str =
case (dropWhile isSpace $ reverse str) of
',':_ -> True
_ -> False
finish :: Monad m => Pipe String String m ()
finish = do
str <- await
yield str
if endsWithComma str
then do
str' <- await
yield str'
else finish
user :: Producer String IO ()
user = Pipes.stdinLn >-> finish
You can then hook up the user Producer to any downstream Consumer. For example, to echo the stream back out you can write:
main = runEffect (user >-> Pipes.stdoutLn)
To learn more about pipes you can read the tutorial.
Sorry, I wrote something wrong in a comment and I thought that now that I understood what you were trying to do, I'd give an answer with a little more substance. The core idea is that you're going to need a state buffer while you loop through the string, as far as I can tell. You have f :: [String] -> [String] but you'll need an extra string of buffer before you can solve this puzzle.
So let me assume an answer which looks like:
chop = joinCommas "" . map (++ "\n") . lines
Then the structure of joinCommas is going to look like:
import Data.List (isSuffixOf)
-- override with however you want to handle the ",\n" between lines.
joinLines = (++)
incomplete = isSuffixOf ",\n"
joinCommas :: String -> [String] -> [String]
joinCommas prefix (line : rest)
| incomplete prefix = joinCommas (joinLines prefix line) rest
| otherwise = prefix : joinCommas line rest
joinCommas prefix []
| incomplete prefix = error "Incomplete input"
| otherwise = [prefix]
The prefix stores up lines until it doesn't end with ",\n" at which point it emits the prefix and continues with the rest of the lines. On EOF we process the last line unless that line is incomplete.
I am getting Non-exhaustive patterns in lambda. I am not sure of the cause yet. Please anyone how to fix it. The code is below:
import Control.Monad
import Data.List
time_spent h1 h2 = max (abs (fst h1 - fst h2)) (abs (snd h1 - snd h2))
meeting_point xs = foldl' (find_min_time) maxBound xs
where
time_to_point p = foldl' (\tacc p' -> tacc + (time_spent p p')) 0 xs
find_min_time min_time p = let x = time_to_point p in if x < min_time then x else min_time
main = do
n <- readLn :: IO Int
points <- fmap (map (\[x,y] -> (x,y)) . map (map (read :: String->Int)) . map words . lines) getContents
putStrLn $ show $ meeting_point points
This is the lambda with the non-exhaustive patterns: \[x,y] -> (x,y).
The non-exhaustive pattern is because the argument you've specified, [x,y] doesn't match any possible list - it only matches lists with precisely two elements.
I would suggest replacing it with a separate function with an error case to print out the unexpected data in an error message so you can debug further, e.g.:
f [x,y] = (x, y)
f l = error $ "Unexpected list: " ++ show l
...
points <- fmap (map f . map ...)
As an addition to #GaneshSittampalam's answer, you could also do this with more graceful error handling using the Maybe monad, the mapM function from Control.Monad, and readMaybe from Text.Read. I would also recommend refactoring your code so that the parsing is its own function, it makes your main function much cleaner and easier to debug.
import Control.Monad (mapM)
import Text.Read (readMaybe)
toPoint :: [a] -> Maybe (a, a)
toPoint [x, y] = Just (x, y)
toPoint _ = Nothing
This is just a simple pattern matching function that returns Nothing if it gets a list with length not 2. Otherwise it turns it into a 2-tuple and wraps it in Just.
parseData :: String -> Maybe [(Int, Int)]
parseData text = do
-- returns Nothing if a non-Int is encountered
values <- mapM (mapM readMaybe . words) . lines $ text
-- returns Nothing if a line doesn't have exactly 2 values
mapM toPoint values
Your parsing can actually be simplified significantly by using mapM and readMaybe. The type of readMaybe is Read a => String -> Maybe a, and in this case since we've specified the type of parseData to return Maybe [(Int, Int)], the compiler can infer that readMaybe should have the local type of String -> Maybe Int. We still use lines and words in the same way, but now since we use mapM the type of the right hand side of the <- is Maybe [[Int]], so the type of values is [[Int]]. What mapM also does for us is if any of those actions fails, the overall computation exits early with Nothing. Then we simply use mapM toPoint to convert values into a list of points, but also with the failure mechanism built in. We actually could use the more general signature of parseData :: Read a => String -> Maybe [(a, a)], but it isn't necessary.
main = do
n <- readLn :: IO Int
points <- fmap parseData getContents
case points of
Just ps -> print $ meeting_point ps
Nothing -> putStrLn "Invalid data!"
Now we just use fmap parseData on getContents, making points have the type Maybe [(Int, Int)]. Finally, we pattern match on points to print out the result of the meeting_point computation or print a helpful message if something went wrong.
If you wanted even better error handling, you could leverage the Either monad in a similar fashion:
toPoint :: [a] -> Either String (a, a)
toPoint [x, y] = Right (x, y)
toPoint _ = Left "Invalid number of points"
readEither :: Read a => String -> Either String a
readEither text = maybe (Left $ "Invalid parse: " ++ text) Right $ readMaybe text
-- default value ^ Wraps output on success ^
-- Same definition with different type signature and `readEither`
parseData :: String -> Either String [(Int, Int)]
parseData text = do
values <- mapM (mapM readEither . words) . lines $ text
mapM toPoint values
main = do
points <- fmap parseData getContents
case points of
Right ps -> print $ meeting_point ps
Left err -> putStrLn $ "Error: " ++ err
What is the best practice to display reasons for a failed property test when it is tested via QuickCheck?
Consider for example:
prop a b = res /= []
where
(res, reason) = checkCode a b
Then the a session could look like:
> quickCheck prop
Falsifiable, after 48 tests:
42
23
But for debugging it would be really convenient to show the reason for failure as part of the quickCheck falsifable report.
I have hacked it like this:
prop a b = if res /= [] then traceShow reason False else True
where
(res, reason) = checkCode a b
Is there is a better/nicer or more quickcheckish way to do it?
I assume that your "reason" variable contains some kind of test-specific data on what went wrong. You could instead return a "Result", which contains both success/fail/invalid conditions and a string explaining what went wrong. Properties that return Results are handled by QuickCheck in exactly the same way as properties that return Bool.
(edit) Like this:
module QtTest where
import Test.QuickCheck
import Test.QuickCheck.Property as P
-- Always return success
prop_one :: Integer -> P.Result
prop_one _ = MkResult (Just True) True "always succeeds" False [] []
-- Always return failure
prop_two :: Integer -> P.Result
prop_two n = MkResult (Just False) True ("always fails: n = " ++ show n) False [] []
Note that it is the "Result" type defined in Test.QuickCheck.Property you want.
There are also some combinators defined in Test.QuickCheck.Property which help you compose the Result rather than calling the constructor directly, such as
prop_three :: Integer -> Property
prop_three n = printTestCase ("always fails: n = " ++ show n) False
I guess it would be better style to use those.
This works in the same way as Paul Johnson's answer but is more concise and robust to changes in MkResult:
import Test.QuickCheck.Property (succeeded, failed, reason)
prop a b =
if res /= []
then succeeded
else failed { reason = reason }
where
(res, reason) = checkCode a b
Because QuickCheck gives you the inputs to the function, and because the code under test is pure (it is, right?), you can just feed those inputs to the function and get the result. This is more flexible, because with those inputs you can also repeatedly test with tweaks to the original function until it's correct.
This is my solution (I use counterexample instead of printTestCase since the later one is deprecated now):
(<?>) :: (Testable p) => p -> String -> Property
(<?>) = flip (Test.QuickCheck.counterexample . ("Extra Info: " ++))
infixl 2 <?>
Usage:
main :: IO ()
main = hspec $ do
describe "math" $ do
prop "sum-of-square-le-square-of-sum" $ do
\(x :: Int) (y :: Int) ->
x * x + y * y <= (x + y) * (x + y) <?> show (x * x, y * y, x + y)
So when a test case fails, you can see something like:
*** Failed! Falsifiable, Falsifiable (after 2 tests):
1
-1
Extra Info: (1,1,0)
You can also use <?> together with .&&., .||., === and ==> etc.:
describe "math" $ do
prop "sum-of-square-le-square-of-sum" $ do
\(x :: Int) (y :: Int) ->
x * x + y * y <= (x + y) * (x + y) <?> show (x * x, y * y, x + y) .||. (1==0) <?> "haha"