I have the following code:
import Debug.Trace (trace)
mtrace :: Show a => String -> a -> a
mtrace msg value =
trace (msg ++ show value) value
isVowel :: Char -> Bool
isVowel = (`elem` "AEIOU")
vowelSlice :: String -> ([Maybe Char], String)
vowelSlice "" = ([], [])
vowelSlice (c:s)
| isVowel c = (Nothing:chars, c:vowels)
| otherwise = (Just c:chars, vowels)
where (chars, vowels) = vowelSlice s
stringTogether :: [Maybe Char] -> String -> String
stringTogether [] "" = ""
stringTogehter (Just c:cs) vowels = c:stringTogether cs vowels
stringTogehter (Nothing:cs) (v:vs) = v:stringTogether cs vs
process :: String -> String
process s = stringTogether (mtrace "chars: " chars) (mtrace "vowels: " cycledVowels)
where
(chars, vowels) = vowelSlice s
cycledVowels = tail vowels ++ [head vowels]
main :: IO ()
main = do
line <- getLine
putStrLn $ process line
for testing I run my file using the runhaskell command and the I enter HELLO PEOPLE as user input once the program is running. I'm expecting the output: HELLE POEPLO or something similar since my program is meant to shift the vowels only. My program works fine until it tries to run the stringTogether method. Specifically the issue lies with the pattern matching, I have an array:
[Just 'H',Nothing,Just 'L',Just 'L',Nothing,Just ' ',Just 'P',Nothing,Nothing,Just 'P',Just 'L',Nothing]
and a pattern
(Just c:cs) vowels that I expect it to match but somehow it doesn't seem to work. When I run the code and enter HELLO WORLD I receive the following error:
18:1-25: Non-exhaustive patterns in function stringTogether I logged a few things using the trace module and everything looks as expected before entering the stringTogether function
I'm probably overlooking something really obvious but I just can't get my head around why the pattern match won't work, I hope someone is able to help. Thanks in advance!
The pattern match fails because of a typo, 2 separate functions were defined instead of the intended one: stringTogether and stringTogehter. The patterns were valid but the compiler failed to find them because they had mismatching names. The function technically stringTogether only had one pattern [] "" so when the list was passed it raised the 18:1-25: Non-exhaustive patterns in function stringTogether error.
Related
I'm doing my Haskell Datentyp homework, and have try to solve this problem for a whole day.
The question is like this .
Use this Datentyp and only one function tokenize, other functions in the library are not permitted.
data Token = Text String
| Placeholder String
deriving (Eq, Show)
tokenize :: String -> [Token]
The brace is the sign of Placeholder
The result should like this:
when we give input"Hallo {name}, {xyz}."
should give [Text "Hallo ", Placeholder "name", Text ", ", Placeholder "xyz", Text "."] out
I have tried for a whole day, only Text output or Placehold is OK, but I have several problems:
How to handle curly brackets {}
How to use pattern match to match "{longtext...}"
Because of Datentype [token], tokenize (x: xs) = x :[ Text (xs:[])] do not works , so how to deal with it
how to combine the comma and all of them together, with only type [token] result function,I have tried ++ and : , but they all report error.
According to 4, there is a common question besides this homework: when using Datentype, and type of result doesn't fits type of input, how to use recursion.
This is the last edition of my answer, it is still far away
data Token = Text String
| Placeholder String
deriving (Eq, Show)
tokenize :: String -> [Token]
tokenize [] = []
tokenize ('{':x:xs) = [ Placeholder (x:xs)]
tokenize (x: xs) = [ Text (x:xs)]
otherwise = error "TODO: Implementierung vervollstaendigen"
The result should like this:
when we give input"Hallo {name}, {xyz}."
should give [Text "Hallo ", Placeholder "name", Text ", ", Placeholder "xyz", Text "."] out
Suppose all the input without internal bracket and are correctly denoted by curly brackets{}
In the real-world, you'd probably want to use a library like Parsec. But for a homework, something like the following is probably enough:
data Token = Text String
| Placeholder String
deriving (Eq, Show)
tokenize :: String -> [Token]
tokenize xs = parseText "" xs
parseText :: String -> String -> [Token]
parseText text ('{':xs) = Text text : parsePlaceholder "" xs
parseText text (x:xs) = parseText (text ++ [x]) xs
parseText text "" = [Text text]
parsePlaceholder :: String -> String -> [Token]
parsePlaceholder name ('}':xs) = Placeholder name : parseText "" xs
parsePlaceholder name (x:xs) = parsePlaceholder (name ++ [x]) xs
parsePlaceholder name "" = [Text name]
main :: IO ()
main = print (tokenize "Hallo {name}, {xyz}.")
Instead of studying the code closely right away, you may want to try to copy only the type signatures of parseText and parsePlaceholder to see whether you can implement them yourself.
A few points of critique:
Appending to the end of a linked list (as I do with text ++ [x] and name ++ [x]) is not very efficient. A possible approach would be to prepend (with (:)) and then in the end do once a reverse.
tokenize "{foo}" returns [Text "",Placeholder "foo",Text ""], which is not so nice, you may want to incorporate the following helper function:
createText "" = []
createText text = [Text text]
Since we are writing a parser, we can benefit a great deal from using traditional parser techniques. The key point is that you want a parse function to parse only a part of the string at once, and so it is most convenient for it to return two things: the tokens parsed so far, and the remainder of the string: what's left to be parsed after handling those tokens.
So, our main recursive function will be
parse :: String -> (String, [Token])
This signature does not match the required signature of tokenize, but it is easy to write tokenize to delegate to it:
tokenize :: String -> [Token]
tokenize s = case parse s of
("", r) -> r
(s, r) -> error ("unexpected text " ++ s)
Makes sense, right? If we parsed the stream and there's somehow text left, something went wrong; otherwise, the remainder is empty, so what's been parsed so far must be all of it.
parse itself is responsible for deciding, based on the first character it sees, whether to produce a Text or a Placeholder. In either case, it consumes the corresponding token, using break to identify the closing } (in the case of Placeholder), or the next opening { (in the case of Text). It conses the generated token onto the result of the recursive call to parse:
parse :: String -> (String, [Token])
parse "" = ("", [])
parse ('{':s) = let (name, ('}':s')) = break (== '}') s
in (Placeholder name :) <$> parse s'
parse s = let (text, s') = break (== '{') s
in (Text text :) <$> parse s'
Note that there is a hidden failure mode here, not exposed in the type signature: if the input contains a { character with no matching }, we will have a runtime error. But the signature of tokenize gives us little other choice: we have no way to indicate an invalid parse in the result type, so we can either lie by claiming there was a valid parse, or terminate the program abnormally; I prefer the latter.
Here's a simple solution, perhaps not efficient though. The general idea is to keep track of which tokens we've already parsed, which chars are to be added to the next Text token and what is left.
First we'll call a helper function named tokenize' (note the single quote at the end) which takes an additional param named partial that is a list of accumulated chars, which are partial Text-type Token.
When we encounter a '{' we scan the rest of the string to split on the first '}', create a Placeholder token and continue to process the rest of the string recursively. If we encounter any other char, we simply append it to partial.
Since it's a homework assignment, I've left the implementation of splitPlaceholder as an exercise.
tokenize :: String -> [Token]
tokenize str = tokenize' str []
partialToText :: String -> [Token]
partialToText [] = []
partialToText xs = [Text xs]
tokenize' :: String -> String -> [Token]
tokenize' [] partial = partialToText partial
tokenize' ('{':xs) partial =
let splitted = splitPlaceholder xs
placeholderText = Placeholder (head splitted)
rest = head $ tail splitted
nextToken = partialToText partial
in nextToken ++ (placeholderText : tokenize' rest [])
tokenize' (x:xs) partial = tokenize' xs (partial ++ [x])
-- split input to two parts, first is everything till the first '}' (not including)
-- and the second is the rest of the input string
splitPlaceholder :: String -> [String]
-- implementation left as an exercise
I'm a new to Haskell. I'm reading an input string (a) and want to return a string when I find a character (e) inside. Now my whole source code:
a = "b,b,b,b/b,b,b/b,b,b,b/e,e,e/w,w,w,w/w,w,w/w,w,w,w"
n = length a
simpleCase n =
case n of
'a' -> "hey cutie"
eLoopCase i =
if i < n
then do
let char = a !! i
case char of
'e' -> putStr $ "(" ++ "found an e" ++ "),"
'w' -> return ()
'b' -> return ()
',' -> eLoopCase (i+1)
'/' -> eLoopCase (i+1)
if (char == ',' || char == '/') == False
then eLoopCase (i+1)
else return ()
else return ()
simpleCase gives me back a string but eLoopCase gives me an IO() back. It works, however I'd like for eLoopCase to give an String back so I can work on it.
:t simpleCase
simpleCase :: Char -> [Char]
:t eLoopCase
eLoopCase :: Int -> IO ()
I understand that this has something to do with monads,then do and putStr, this is where my understanding ends. Removing do gives a parse error.
eLoopCase is returning nothing because you have return () at all the "ends" of it. I think you're after something like this (Notice appending the current character to the result of the recursive call in the x == 'w' || x == 'b' branch):
a :: String
a = "b,b,b,b/b,b,b/b,b,b,b/e,e,e/w,w,w,w/w,w,w/w,w,w,w"
eLoopCase :: String -> IO String
eLoopCase [] = return []
eLoopCase (x:xs)
| x == 'e' = do
putStrLn "(found an e)"
return [x]
| x == ',' || x == '/' =
eLoopCase xs
| x == 'w' || x == 'b' = do
rest <- eLoopCase xs
return (x : rest)
| otherwise = do
putStrLn ("Encountered invalid character: " ++ show x)
return []
General problems with your code:
The program you wrote is very imperative in style. This is something I would urge you to try to move away from while writing Haskell.
Prefer pattern matching on lists over indexing with !!.
I should note that the function I provided has flaws of its own. It presupposes that the strings provided to it will only consist of a couple different chars. A way to improve it would be to add an otherwise branch to the guards. (Edit: Added to the snippet above)
I think it's also worth pointing out that this function really need not depend on IO at all to work. Look into other "pure" alternatives for doing error handling/reporting such as Either, Maybe, and Writer.
I'm glad you've decided to try to learn Haskell. You can do a lot better than eLoopCase. I'll tell you how, but first I'll explain the problem you were having in your original question and how you fixed it.
As originally written, eLoopCase is has a type Int -> IO (), meaning it is a function which takes an Int and returns an input output action. IOW, the type tells you that if you give it a number it will do something. If you look at the code you can see that that something is just printing out strings, but it could have been almost anything.
In your answer, you rewrote eLoopCase to construct strings directly via the ++ operator, instead of printing them out to the terminal via putStr. This is the reason your rewritten function has the type that it does. It also explains why you no longer need the return () statements, which are the "Do nothing while returning a () value" IO actions.
I hope that clears things up a little. That said, eLoopCase can be tremendously improved.
Haskell programs are efficiently written when the control logic matches the data structure. For instance, this program is iterating through a list. A list is defined as the data which is either an empty list or an element and more list, as seen in the declaration below.
data List a = []
| a : List a
Consequently, programs which iterate through a list will be based on decisions for those two constructors. For example (using the synonym String for [Char]), eLoopCase can be rewritten as
eLoopCase' :: String -> String
eLoopCase' [] = ""
eLoopCase' (a:as) = evalCase a ++ eLoopCase' as
evalCase a = case a of
'e' -> "(" ++ "found an e" ++ "),"
'w' -> ""
'b' -> ""
',' -> ""
'/' -> ""
_ -> ""
Notice eLoopCase' needs to be fed a as an input as it is no longer hard coded into the body of the function--a good thing. It also does away with the index i and errors arising from using !! (try calling eLoopCase (-1)).
Having practice in writing recursive functions such as eLoopCase' is a good start. An evolution in programming is to see what you are intending to do with that loop and applying appropriate patterns.
For instance, since you want to evaluate every element in a list by a certain function, use a map. Specifically map evalCase to go from a list of characters to your list of strings, then use concat to append all those lists together:
eLoopCase'' = concat . map evalCase
Actually I've answered my own question. The following seems to work:
a = "b,b,b/b,b,b/b,b,b,b/e,e,e/w,w,w,w/w,w,w/w,w,w,w"
n = length a
eLoopCase i =
if i < n
then
case a !! i of
'e' -> "(" ++ "found an e" ++ ")," ++ eLoopCase (i+1)
'w' -> "" ++ eLoopCase (i+1)
'b' -> "" ++ eLoopCase (i+1)
',' -> eLoopCase (i+1)
'/' -> eLoopCase (i+1)
else ""
I'm still curious as to what happened.
I want to write a function that gets the first integer in a string, if the integer is at the beginning of the string and is followed by space or nothing.
For example, "12" and "12 kids" would be valid strings, but "12kids", "a12" are invalid.
This is my function:
getFirstInteger :: String -> Int
getFirstInteger [] = error "No integer"
getFirstInteger str
| dropWhile (Char.isNumber) str == [] = read str :: Int
| Char.isSpace $ head $ dropWhile (Char.isNumber) str = read (takeWhile (Char.isNumber) str) :: Int
| otherwise = error "No integer found"
The problem is that if the string is actually an integer, head will raise an exception, so that is why the first condition exists. Is there any elegant solution to this problem?
getFirstInteger :: String -> Int
getFirstInteger = read . head . words
words will split the String into a list of Strings, which were originally separated by whitespace. head will take the first (or error if the original string was empty), and read will parse the string as usual (and error if the first word wasn't a valid Int).
However, I prefer a variant that doesn't use error on empty Strings or unparseable ones, e.g.
import Text.Read (readMaybe)
getFirstInteger :: String -> Maybe Int
getFirstInteger [] = Nothing
getFirstInteger xs = readMaybe . head . words $ xs
One could write this completely point-free with listToMaybe from Data.Maybe, but that's probably an overkill:
import Data.Maybe (listToMaybe)
import Text.Read (readMaybe)
import Control.Monad ((>=>))
getFirstInteger :: String -> Maybe Int
getFirstInteger = listToMaybe . words >=> readMaybe
If you want to parse strings without using parser combinator libraries or any of the machinery in Text.Read, have a look at the functions break and span:
span :: (a -> Bool) -> [a] -> ([a], [a])
break :: (a -> Bool) -> [a] -> ([a], [a])
The nice thing is that both of these functions not only return what they match but also the remainder of the string allowing you to continue your parsing.
To solve your problem:
import Data.Char
getFirstInteger :: String -> Maybe Int
getFirstInteger str
let (digs, rest1) = span isDigit str
endsok = case rest1 of
[] -> True
(c:_) -> c == ' '
in
if not (null digs) && endsok
then Just (read digs)
else Nothing -- either no digits or doesn't end properly
This version does not allow a leading minus sign. This next version allows an optional leading minus sign for the integer:
getFirstInteger' str =
let (minus,rest1) = span (=='-') str
(digs, rest2) = span isDigit rest1
endsok = case rest2 of
[] -> True
(c:_) -> c == ' '
in
if length minus <= 1 && not (null digs) && endsok
then Just (read (minus ++ digs))
else Nothing
Yes - this does not terminate as early as possible on bad input. I provide it mainly as an example of how to chain together calls to span and break.
Use reads. For example:
type Unit = String
readUnit :: String -> Maybe (Int, Maybe Unit)
readUnit s = case reads s of -- the integer is at the beginning of the string and...
(n, ' ':unit):_ -> Just (n, Just unit) -- is followed by space...
(n, "" ):_ -> Just (n, Nothing) -- or nothing.
_ -> Nothing
In ghci:
> readUnit "12"
Just (12,Nothing)
> readUnit "12 kids"
Just (12,Just "kids")
> readUnit "12kids"
Nothing
> readUnit "a12"
Nothing
However, there are a few minor considerations to keep in mind. It's possible that read does not restrict the syntax as much as you might want; for example, the following answer may surprise you:
> readUnit " ((-0x5)) kids"
Just (-5,Just "kids")
You may also want to drop extraneous spaces in the unit; for example, you could change the first clause above to
(n, ' ':unit):_ -> Just (n, Just (dropWhile isSpace unit))
or similar. And as a final variation on this theme, note that while the standard instances of Read never return lists with more than one element from reads, it is technically possible that some user-supplied type may do so. So if you were ever to use reads to parse types other than Int, you may want to either demand an unambiguous parse or consider all the parses before deciding what to do; the above code bakes in the assumption that the first parse is as good as any.
I want to write a program in Haskell which will take command line arguments. For example: to print the sum of the first 6 elements of the series (which will be calculated by another function), I will write:
sum 6
and the correct answer should be displayed. I have to do this for another 5-7 different commands by checking the command line. How should I do it? Is switch case a good idea? If so, can anyone tell me how it can be done.
SOLUTION:
main = do
--Get some input
f <- getLine
--Split the input into 2 strings; one is COMMAND field and other is the ARGUMENT field using the condition the there is one space between them
let cmd = takeWhile (/=' ') f
let arg = dropWhile (/=' ') f
let val = tail arg
let p = read val::Int
--Check for the COMMAND
case cmd of
"SUM" -> if (empty arg) then do { putStrLn "ERR"; exitWith ExitSuccess} else if (check val) then print (sum1 p) else do { putStrLn "ERR"; exitWith ExitSuccess}
"NTH" -> if (empty arg) then do { putStrLn "ERR"; exitWith ExitSuccess} else if (check val) then print (fact p) else do { putStrLn "ERR"; exitWith ExitSuccess}
"BOUNDS" -> if (empty arg) then do { putStrLn "ERR"; exitWith ExitSuccess} else if (check val == False) then do { putStrLn "ERR"; exitWith ExitSuccess} else if (p > 1) then do { print c; print d} else do { putStrLn"ERR"; exitWith ExitSuccess}
"QUIT" -> if (empty arg) then exitWith ExitSuccess else do { putStrLn "ERR"; exitWith ExitSuccess}
_ -> do { putStrLn "ERR"; exitWith ExitSuccess}
--Repeat main until QUIT
main
optparse-applicative is one example of a library which supports this kind of sub-command parsing.
Let's say your program has two commands for now, "sum" and "mean". We can represent the command and its arguments using an algebraic data type, here called Command.
import Data.Monoid (mconcat)
import Options.Applicative
data Command = Sum Integer
| Mean Integer
-- et cetera
We can build a parser which accepts all of the commands, by writing parsers for each individual command, and composing them.
parseNumber :: Parser Integer
parseNumber = argument auto (metavar "N")
sumParser :: ParserInfo Command
sumParser = info (Sum <$> parseNumber)
(progDesc "Sum first N elements in series")
meanParser :: ParserInfo Command
meanParser = info (Mean <$> parseNumber)
(progDesc "Mean of first N elements in series")
commandParser :: ParserInfo Command
commandParser = info commands $ progDesc "My program" where
commands = subparser $ mconcat [
command "sum" sumParser
, command "mean" meanParser
]
If you are wondering what Parser and ParserInfo are about: Usually we build a Parser, then put it into a ParserInfo, using the info combinator to decorate it with additional information about how it should be run (for example, with progDesc). Parsers may be composed with other Parsers, typically using the applicative combinators, but a ParserInfo is only a Functor, as it represents the entry point to the program.
Since each command is like a little sub-program, we need a ParserInfo for each one. The command and subparser combinators let us take some ParserInfos and wrap them up in a Parser, turning multiple entry points into one.
Once we have a result from the parser, we can dispatch to the appropriate routine by pattern matching on the result.
main :: IO ()
main = do
cmd <- execParser commandParser
case cmd of
Sum n -> return () -- TODO perform sum command
Mean n -> return () -- TODO perform mean command
Of course, if you have the time and the need, is much better to use a command line parser library than a switch case. A proper parser gives you the ability to have flags in any order, automatic documenation etc ... Although if you don't need any of this now, you might need it later.
However, pattern matching allows you check value(s) within a list, but although the size of the list, and this at the same time. This makes writing poor man command line parsing dead-easy in Haskell.
Example
main = do
args <- getArg
case args of
["command1", a, b] -> command1 a b -- 2 argument
["command2", a ] -> command2 a -- 1 argument
"command3":as -> command3 as -- n arguments
otherwise -> putStrLn "Please read the code to see which arguments are acceptable :-)"
So even though I would propably recommend using a parsing library, if you only need a couple of options without flags , and don't have time to learn/choose one, a simple case ... of is pretty neat and much quicker/simpler to write.
You can write your own simple applicative-style parser in just a few lines. The idea is: accept a list of string pairs, where the first string is an option name and the second string is an option value, lookup for a current option name, and if it's found, treat the associated value somehow and delete the pair from the list. If it's not found, return Nothing. So Parser is defined like this:
type Parser = StateT [(String, String)] Maybe
And here is the main function:
option :: (String -> Maybe a) -> String -> Parser a
option f str = StateT $ \xs -> do
(v, xs') <- lookupDelete str xs
v' <- f v
return (v', xs')
where lookupDelete does what it says. Actual option parsers are:
sopt :: String -> Parser String
sopt = option Just
opt :: Read a => String -> Parser a
opt = option $ reads >>> listToMaybe >=> finish
finish (x, []) = Just x
finish _ = Nothing
The opt parser tries to read a string, and it succeeds if the string is read fully.
optPairs [] = Just []
optPairs (('-':'-':name):opt:xs) = ((name, opt) :) <$> optPairs xs
optPairs _ = Nothing
This function splits input into pairs. And lastly
parse :: Parser a -> String -> Maybe a
parse p = words >>> optPairs >=> runStateT p >=> finish
Here is an example:
data SubCommand = SubCommand String (Double, Double)
deriving (Show)
data Command = Sum [Integer]
| Sub SubCommand
deriving (Show)
subcommandParser :: Parser SubCommand
subcommandParser = SubCommand <$> sopt "str" <*> opt "dbls"
commandParser :: Parser Command
commandParser = Sum <$> opt "sum" <|> Sub <$> subcommandParser
main = mapM_ (print . parse commandParser)
[ "--sum [1,2,3,4]"
, "--str option --dbls (2.2,0)"
, "--dbls (2.2,0) --str option"
, "--smth smth"
]
Results in
Just (Sum [1,2,3,4])
Just (Sub (SubCommand "option" (2.2,0.0)))
Just (Sub (SubCommand "option" (2.2,0.0)))
Nothing
The whole code: http://lpaste.net/114365
I have a function to count no of times each word is repeated in a string:
keywords :: String -> [String]
keywords = words . map (\x -> if isAlpha x then x else ' ')
count :: Ord a => [a] -> [(a,Int)]
count = map (head &&& length) . group . sort
wordcount = count . keywords
which works perfectly.
I want to read a text file as input to this function using the IO. I did the coding like this:
wordcou :: IO ()
wordcou =
do
putStr "Please text file name :"
textfile <- getLine
text <- readFile textfile
let result = wordcount text
putStr result
The IO function is giving me an error. Can any one help me fix this error please?
error is
ERROR file:.\project.hs:194 - Type error in application
*** Expression : putStr result
*** Term : result
*** Type : [([Char],Int)]
*** Does not match : [Char]
Your code has 2 problems:
wordcou should be of type IO (), since it doesn't return anything
putStr should be replaced by print because result is not a String
After these changes, your code compiles and runs fine.
Add a type declaration for wordcount.
Look at the types and definitions of of putStr and print.
Do you see the difference?