This is my code
module Main where
import Control.Monad (mapM)
import Text.Read (readMaybe)
import System.IO (BufferMode(..), stdout, hSetBuffering)
mouth = [('P',0),('(',1),('[',2),(')',3),('O',4)]
eyes = [(':',1),('8',2),(';',3)]
findKey :: (Eq k) => k -> [(k,v)] -> Maybe v
findKey key = foldr (\(k,v) acc -> if key == k then Just v else acc) Nothing
query :: Read a => String -> IO a
query prompt = do
putStr $ prompt ++ ": "
val <- readMaybe <$> getLine
case val of
Nothing -> do
putStrLn "Sorry that's a wrong value - please reenter"
query prompt
Just v -> return v
ngoers :: IO Int
ngoers = query "Enter the number of Concertgoers"
cgoers :: Int -> IO (Int, Double)
cgoers i = do
c <- query prompt
return (fromIntegral i,c)
where prompt = "Enter the emoticon for concertgoer " ++ show (i+1)
concertgoer :: IO [(Int, Double)]
concertgoer = do
n <- ngoers
mapM cgoers [0,1..n-1]
presentResult :: Double -> IO ()
presentResult v = putStrLn $ "The results are: " ++ show v
main :: IO ()
main = do
p <- concertgoer
presentResult $ 0
I want this output
Enter the number of Concertgoers: 4
Enter the emoticon for concertgoer 1: :(
Enter the emoticon for concertgoer 2: :)
Enter the emoticon for concertgoer 3: ;P
Enter the emoticon for concertgoer 4: ;o
The results are: 2 4 3 7
From your example I'm guessing that you match each eye and mouth to a number, and a emoticon is the sum if those... but you haven't explained nothing of this in your post. Assuming so, this is a very naive way to write It
import Control.Monad (mapM)
-- Define the data you want to use
data Eye = Normal
| Glasses
| Wink
deriving(Show, Eq)
data Mouth = P
| Sad
| Bracket
| Happy
| O
deriving(Show, Eq)
data Face = Face Eye Mouth deriving(Show, Eq)
-- Define special readers and elemToInt
readEyes :: Char -> Maybe Eye
readEyes c = case c of
':' -> Just Normal
'8' -> Just Glasses
';' -> Just Wink
_ -> Nothing
-- This is equivalent to derive Enum class and apply fromEnum. Try to do it your self ;)
eyeToInt :: Eye -> Int
eyeToInt Normal = 1
eyeToInt Glasses = 2
eyeToInt Wink = 3
readMouth :: Char -> Maybe Mouth
readMouth c = case c of
'P' -> Just P
'(' -> Just Sad
'[' -> Just Bracket
')' -> Just Happy
'O' -> Just O
_ -> Nothing
mouthToInt :: Mouth -> Int
mouthToInt P = 0
mouthToInt Sad = 1
mouthToInt Bracket = 2
mouthToInt Happy = 3
mouthToInt O = 4
readFace :: String -> Maybe Face
readFace [] = Nothing
readFace [e,m] = do
eye <- readEyes e
mouth <- readMouth m
return $ Face eye mouth
readFace _ = Nothing
faceToInt :: Face -> Int
faceToInt (Face e m) = eyeToInt e + mouthToInt m
-- The main loop is straight forward
main :: IO ()
main = do
putStrLn "Enter the number of Concertgoers"
number <- read <$> getLine -- Use safe reading better... I am using an online repl so no access to it
results <- mapM getEmoticon [1..number]
putStrLn $ "The results are: " ++ show results
where getEmoticon n = do
putStrLn $ "Enter the emoticon for concertgoer " ++ show n
face <- readFace <$> getLine
case face of
Nothing -> do
putStrLn "That's not an emotion!!"
getEmoticon n
Just f -> return $ faceToInt f
I think It is what you expect but let me know
Related
As an exercise in learning Haskell I've written an interpreter for the CESIL language (an old, very basic, educational low level language). It works, but compared to implementations I've written in other compiled languages it's very slow, even when compiled with -O2, and only a little faster than Python. Timing a large CESIL program with time gives:
Haskell:
real 0m0.346s
user 0m0.199s
sys 0m0.016s
Go:
real 0m0.243s
user 0m0.003s
sys 0m0.007s
Python:
real 0m0.414s
user 0m0.387s
sys 0m0.004s
Here's the main execution part of the code where most of the time is spent, and which I would like to speed up. I'm new to Haskell, and I'm sure there are better, cleaner ways of writing some of this, but my main concern at the moment is the speed. Hopefully I've included enough to make sense:
-- Define the computer state
data Computer =
Computer
{ program :: Array Integer Instruction
, dataVals :: [Integer]
, ram :: Map.Map String Integer
, acc :: Integer
, pc :: Integer
, steps :: Integer
, halted :: Bool
}
-- Initialise the computer and run the program
runProgram ::
Array Integer Instruction -> [Integer] -> Params -> ExceptT String IO ()
runProgram pr dv pars = do
let comp =
Computer
{ program = pr
, dataVals = dv
, ram = Map.empty
, acc = 0
, pc = 0
, steps = 0
, halted = False
}
comp' <- execute comp pars
if countSteps pars
then liftIO . putStrLn $ "Steps executed: " ++ (show $ steps comp')
else return ()
-- Main execution "loop"
execute :: Computer -> Params -> ExceptT String IO Computer
execute comp pars = do
liftEither $ checkPC comp
(comp', output) <- liftEither $ step comp
liftIO $ putStr output
case () of
_
| halted comp' -> return comp'
| Just (steps comp') == maxSteps pars -> do
liftIO $
putStrLn $
"Execution halted after " ++ (show $ steps comp') ++ " steps."
return comp'
| otherwise -> execute comp' pars
-- Check program counter is in range.
checkPC :: Computer -> Either String ()
checkPC comp =
if pc comp >= (toInteger . length . program $ comp) || pc comp < 0
then Left $ "PC OUT OF RANGE: " ++ (show $ pc comp) ++ "\n"
else Right ()
-- Execute a single step/cycle
step :: Computer -> Either String (Computer, String)
step comp = do
let Instruction lineNo label opCode operand =
program comp ! (fromIntegral . pc $ comp)
comp' = comp {pc = pc comp + 1, steps = steps comp + 1}
case opCode of
IN ->
if null $ dataVals comp
then Left $ "Data exhausted at line " ++ show lineNo ++ "\n"
else let a:dv = dataVals comp
in Right (comp {acc = a, dataVals = dv, pc = pc comp + 1}, "")
OUT -> Right (comp', printf "%8d" $ acc comp)
LINE -> Right (comp', "\n")
PRINT ->
let TextOperand s = operand
in Right (comp', s)
HALT -> Right (comp' {halted = True}, "")
LOAD -> do
n <- getVal operand comp' lineNo
Right (comp' {acc = n}, "")
STORE ->
let SymbolOperand s = operand
ram' = Map.insert s (acc comp') (ram comp')
in Right (comp' {ram = ram'}, "")
ADD -> do
n <- getVal operand comp' lineNo
let a = acc comp' + n
Right (comp' {acc = a}, "")
SUBTRACT -> do
n <- getVal operand comp' lineNo
let a = acc comp' - n
Right (comp' {acc = a}, "")
MULTIPLY -> do
n <- getVal operand comp' lineNo
let a = acc comp' * n
Right (comp' {acc = a}, "")
DIVIDE -> do
n <- getVal operand comp' lineNo
if n == 0
then Left $ "Divide by zero error at line " ++ show lineNo ++ "\n"
else let a = acc comp' `div` n
in Right (comp' {acc = a}, "")
JUMP -> do
let AddrOperand a = operand
Right (comp' {pc = a}, "")
JIZERO -> do
let AddrOperand a = operand
comp'' =
if acc comp' == 0
then comp' {pc = a}
else comp'
Right (comp'', "")
JINEG -> do
let AddrOperand a = operand
comp'' =
if acc comp' < 0
then comp' {pc = a}
else comp'
Right (comp'', "")
NoOp -> Right (comp' {steps = steps comp}, "")
-- Get the value of a numeric operand, which may be a literal constant
-- or a reference to a stored variable.
getVal :: Operand -> Computer -> LineNo -> Either String Integer
getVal (ValueOperand (Left n)) _ _ = Right n
getVal (ValueOperand (Right s)) comp lineNo =
case Map.lookup s $ ram comp of
Just n -> Right n
Nothing ->
Left $ "Unknown variable: '" ++ s ++ "' at line " ++ show lineNo ++ "\n"
As others have pointed out, you're not actually comparing apples to apples here - you've chosen types which are well known to be inefficient - String, Integer, []. So, in order of things to try:
Profile your code - we can make guesses about what might be slow but only the program can tell us if that's true. GHC 9.2 has made some nice improvements in profiling optimised code, see https://well-typed.com/blog/2022/05/hasura-supports-haskell-tooling/. Covering how to do profiling is a topic too large to go into here, but there is a lot of documentation available: https://downloads.haskell.org/ghc/latest/docs/html/users_guide/profiling.html
Try basic improvements to the types you use, stop using String and switch to ByteString, use Int instead of Integer (you'll lose the ability to do arbitrary precision calculations but I assume CESIL was never intended to do that). Using a HashMap instead of a Map might see some improvements, but you'll have to benchmark to know.
Be more explicit about strictness - most, if not all, of the fields in the Computer type could be made strict to tell the compiler "Always evaluate this, there's no need for it to be lazy":
data Computer =
Computer
{ program :: Array Int Instruction
, dataVals :: [Int]
, ram :: !HashMap ByteString Int
, acc :: !Int
, pc :: !Int
, steps :: !Int
, halted :: Bool
}
Doing this will also remove many of the conversions you had between Integer and Int which are unnecessary (unless you really want your program to work with programs with more than 9,223,372,036,854,775,807 instructions)
I'm new to Haskell and trying to write simple program to find maximal element and it's index from intput. I receive values to compare one by one. Maximal element I'm holding in maxi variable, it's index - in maxIdx. Here's my program:
loop = do
let maxi = 0
let maxIdx = 0
let idx = 0
let idxN = 0
replicateM 5 $ do
input_line <- getLine
let element = read input_line :: Int
if maxi < element
then do
let maxi = element
let maxIdx = idx
hPutStrLn stderr "INNER CHECK"
else
hPutStrLn stderr "OUTER CHECK"
let idx = idxN + 1
let idxN = idx
print maxIdx
loop
Even though I know elements coming are starting from bigger to smaller (5, 4, 3, 2, 1) program enters INNER CHECK all the time (it should happen only for the first element!) and maxIdx is always 0.
What am I doing wrong?
Thanks in advance.
Anyway, let's have fun.
loop = do
let maxi = 0
let maxIdx = 0
let idx = 0
let idxN = 0
replicateM 5 $ do
input_line <- getLine
let element = read input_line :: Int
if maxi < element
then do
let maxi = element
let maxIdx = idx
hPutStrLn stderr "INNER CHECK"
else
hPutStrLn stderr "OUTER CHECK"
let idx = idxN + 1
let idxN = idx
print maxIdx
loop
is not a particularly Haskelly code (and as you know is not particularly correct).
Let's make if Haskellier.
What do we do here? We've an infinite loop, which is reading a line 5 times, does something to it, and then calls itself again for no particular reason.
Let's split it:
import Control.Monad
readFiveLines :: IO [Int]
readFiveLines = replicateM 5 readLn
addIndex :: [Int] -> [(Int, Int)]
addIndex xs = zip xs [0..]
findMaxIndex :: [Int] -> Int
findMaxIndex xs = snd (maximum (addIndex xs))
loop :: ()
loop = loop
main :: IO ()
main = do xs <- readFiveLines
putStrLn (show (findMaxIndex xs))
snd returns the second element from a tuple; readLn is essentially read . getLine; zip takes two lists and returns a list of pairs; maximum finds a maximum value.
I left loop intact in its original beauty.
You can be even Haskellier if you remember that something (huge expression) can be replaced with something $ huge expression ($ simply applies its left operand to its right operand), and the functions can be combined with .: f (g x) is the same as (f . g) x, or f . g $ x (see? it's working for the left side as well!). Additionally, zip x y can be rewritten as x `zip` y
import Control.Monad
readFiveLines :: IO [Int]
readFiveLines = replicateM 5 readLn
addIndex :: [Int] -> [(Int, Int)]
addIndex = (`zip` [0..])
findMaxIndex :: [Int] -> Int
findMaxIndex = snd . maximum . addIndex
main :: IO ()
main = do xs <- readFiveLines
putStrLn . show . findMaxIndex $ xs
As for debug print, there's a package called Debug.Trace and a function traceShow which prints its first argument (formatted with show, hence the name) to stderr, and returns its second argument:
findMaxIndex :: [Int] -> Int
findMaxIndex = snd . (\xs -> traceShow xs (maximum xs)) . addIndex
That allows you to tap onto any expression and see what's coming in (and what are the values around — you can show tuples, lists, etc.)
I think alf's answer is very good, but for what it's worth, here's how I would interpret your intention.
{-# LANGUAGE FlexibleContexts #-}
module Main where
import System.IO
import Control.Monad.State
data S = S { maximum :: Int
, maximumIndex :: Int
, currentIndex :: Int }
update :: Int -> Int -> S -> S
update m mi (S _ _ ci) = S m mi ci
increment :: S -> S
increment (S m mi ci) = S m mi (ci+1)
next :: (MonadIO m, MonadState S m) => m ()
next = do
S maxi maxIdx currIdx <- get
input <- liftIO $ getLine
let element = read input :: Int
if maxi < element
then do
modify (update element currIdx)
liftIO $ hPutStrLn stderr "INNER CHECK"
else
liftIO $ hPutStrLn stderr "OUTER CHECK"
modify increment
run :: Int -> IO S
run n = execStateT (replicateM_ n next) (S 0 0 0)
main :: IO ()
main = do
S maxi maxIdx _ <- run 5
putStrLn $ "maxi: " ++ (show maxi) ++ " | maxIdx: " ++ (show maxIdx)
This uses a monad transformer to combine a stateful computation with IO. The get function retrieves the current state, and the modify function lets you change the state.
This question already has answers here:
How to get normal value from IO action in Haskell
(2 answers)
Closed 7 years ago.
I just started learning Haskell and got my first project working today. Its a small program that uses Network.HTTP.Conduit and Graphics.Rendering.Chart (haskell-chart) to plot the amount of google search results for a specific question with a changing number in it.
My problem is that simple-http from the conduit package returns a monad (I hope I understood the concept of monads right...), but I only want to use the ByteString inside of it, that contains the html-code of the website. So until now i use download = unsafePerformIO $ simpleHttp url to use it later without caring about the monad - I guess that's not the best way to do that.
So: Is there any better solution so that I don't have to carry the monad with me the whole evaluation? Or would it be better to leave it the way the result is returned (with the monad)?
Here's the full program - the mentioned line is in getResultCounter. If things are coded not-so-well and could be done way better, please remark that too:
import System.IO.Unsafe
import Network.HTTP.Conduit (simpleHttp)
import qualified Data.ByteString.Lazy.Char8 as L
import Graphics.Rendering.Chart.Easy
import Graphics.Rendering.Chart.Backend.Cairo
numchars :: [Char]
numchars = "1234567890"
isNum :: Char -> Bool
isNum = (\x -> x `elem` numchars)
main = do
putStrLn "Please input your Search (The first 'X' is going to be replaced): "
search <- getLine
putStrLn "X ranges from: "
from <- getLine
putStrLn "To: "
to <- getLine
putStrLn "In steps of (Only whole numbers are accepted):"
step <- getLine
putStrLn "Please have some patience..."
let range = [read from,(read from + read step)..read to] :: [Int]
let searches = map (replaceX search) range
let res = map getResultCounter searches
plotList search ([(zip range res)] :: [[(Int,Integer)]])
putStrLn "Done."
-- Creates a plot from the given data
plotList name dat = toFile def (name++".png") $ do
layout_title .= name
plot (line "Results" dat)
-- Calls the Google-site and returns the number of results
getResultCounter :: String -> Integer
getResultCounter search = read $ filter isNum $ L.unpack parse :: Integer
where url = "http://www.google.de/search?q=" ++ search
download = unsafePerformIO $ simpleHttp url -- Not good
parse = takeByteStringUntil "<"
$ dropByteStringUntil "id=\"resultStats\">" download
-- Drops a ByteString until the desired String is found
dropByteStringUntil :: String -> L.ByteString -> L.ByteString
dropByteStringUntil str cont = helper str cont 0
where helper s bs n | (bs == L.empty) = L.empty
| (n >= length s) = bs
| ((s !! n) == L.head bs) = helper s (L.tail bs) (n+1)
| ((s !! n) /= L.head bs) = helper s (L.tail bs) 0
-- Takes a ByteString until the desired String is found
takeByteStringUntil :: String -> L.ByteString -> L.ByteString
takeByteStringUntil str cont = helper str cont 0
where helper s bs n | bs == L.empty = bs
| n >= length s = L.empty
| s !! n == L.head bs = L.head bs `L.cons`
helper s (L.tail bs) (n + 1)
| s !! n /= L.head bs = L.head bs `L.cons`
helper s (L.tail bs) 0
-- Replaces the first 'X' in a string with the show value of the given value
replaceX :: (Show a) => String -> a -> String
replaceX str x | str == "" = ""
| head str == 'X' = show x ++ tail str
| otherwise = head str : replaceX (tail str) x
This is a lie:
getResultCounter :: String -> Integer
The type signature above is promising that the resulting integer only depends on the input string, when this is not the case: Google can add/remove results from one call to the other, affecting the output.
Making the type more honest, we get
getResultCounter :: String -> IO Integer
This honestly admits it's going to interact with the external world. The code then is easily adapted to:
getResultCounter search = do
let url = "http://www.google.de/search?q=" ++ search
download <- simpleHttp url -- perform IO here
let parse = takeByteStringUntil "<"
$ dropByteStringUntil "id=\"resultStats\">" download
return (read $ filter isNum $ L.unpack parse :: Integer)
Above, I tried to preserve the original structure of the code.
Now, in main we can no longer do
let res = map getResultCounter searches
but we can do
res <- mapM getResultCounter searches
after importing Control.Monad.
Is there a way to read an integer from the console in Haskell? I'm asking for something pretty much like C++'s cin or Java's Scanner.nextInt().
And by that I mean that given this input:
1 2 3
2 3
4 25 12 7
1
I should be able to read them all, not at the same time (maybe reading 4 of them, doing some calculations and then read the rest) ignoring the fact that they are in separate lines.
The easiest solution is probably
getAll :: Read a => IO [a]
getAll = fmap (fmap read . words) getContents
getInts :: IO [Int]
getInts = getAll
which will read all input into a single list.
When in doubt, use Parsec! (not always, and not really, but who cares)
import Text.ParserCombinators.Parsec
import Text.Parsec.Numbers
value = do
spaces
num <- parseFloat
return num
line = many value
then "rinse and repeat", with getLine until you EOF.
Note: you can do it without Parsec using read and friends, but this way is more extendable and preferred for more complicated grammars.
Using Parsec:
import Text.ParserCombinators.Parsec
import Text.Parsec.Numbers
import Control.Applicative ((*>), (<*))
line = spaces *> many1 (parseFloat <* spaces)
main = putStrLn "Enter numbers:" >> fmap (parse line "") getLine >>= print
Running it:
$ ghc parsenums.hs
$ ./parsenums
Enter numbers:
345 23 654 234
[345.0,23.0,654.0,234.0]
A more "manual" way to do it would be something like:
import Data.Char (isDigit, isSpace)
getInts :: String -> [Int]
getInts s = case span isDigit (dropWhile isSpace s) of
("", "") -> []
("", s) -> error $ "Invalid input: " ++ s
(digits, rest) -> (read digits :: Int) : getInts rest
Which might be much clearer to see how it works. In fact, here's one that's completely from the ground up:
getInts :: String -> [Int]
getInts s = case span isDigit (dropWhile isSpace s) of
("", "") -> []
("", s) -> error $ "Invalid input: " ++ s
(digits, rest) -> strToInt digits : getInts rest
isDigit :: Char -> Bool
isDigit c = '0' <= c && c <= '9'
isSpace :: Char -> Bool
isSpace c = c `elem` " \t\n\r"
charToInt :: Char -> Int
charToInt c = fromEnum c - 48
strToInt :: String -> Int
strToInt s = go 0 s where
go n [] = n
go n (c:rest) = go (n * 10 + charToInt c) rest
I want a function that looks something like this
readFunc :: String -> (Float -> Float)
which operates something like this
>(readFunc "sin") (pi/2)
>1.0
>(readFunc "(+2)") 3.0
>5.0
>(readFunc "(\x -> if x > 5.0 then 5.0 else x)") 2.0
>2.0
>(readFunc "(\x -> if x > 5.0 then 5.0 else x)") 7.0
>5.0
The incredibly naive approach (note this must be compiled with {-# LANGUAGE FlexibleContexts #-})
readFunc :: (Read (Float -> Float)) => String -> (Float -> Float)
readFunc s = read s
gives
No instance for (Read (Float -> Float)) ...
Which makes sense since no such instance exists. I understand that I can parse the input string character by character by writing a map from String to Float -> Float but I want to be able to parse at least the most common functions from prelude, and even that would be way more work than I want to commit to. Is there an easy way of doing this?
Just one solution using hint
import Language.Haskell.Interpreter hiding (typeOf)
import Data.Typeable (typeOf)
data Domain = Dom Float Float Float Float Domain
| SDom Float Float Float Float
deriving (Show, Read)
--gets all the points that will appear in the domain
points (SDom a b c d) m = [(x, y)|x <- [a, a+m .. b], y <- [c, c+m .. d]]
points (Dom a b c d next) m = points next m ++ [(x, y)|x <- [a, a+m .. b], y <- [c, c+m .. d]]
readFunc = do
putStrLn "Enter a domain (as Dom x-min x-max y-min y-max subdomain, or, SDom x-min x-max y-min y-max)"
domain' <- getLine
let domain = (read domain') :: Domain
--
putStrLn "Enter a mesh size"
meshSize' <- getLine
let meshSize = (read meshSize') :: Float
--
putStrLn "Enter an initial value function (as f(x,y))"
func' <- getLine
values' <- runInterpreter $ setImports["Prelude"] >>
eval ("map (\\(x,y) -> " ++ func' ++ ")" ++ show (points domain meshSize))
let values = (\(Right v) -> (read v)::([Float])) values'
--the haskell expression being evaluated
putStrLn $ ("map (\\(x,y) -> " ++ func' ++ ")" ++ show (points domain meshSize))
--prints the actual values
putStrLn $ show values
--the type is indeed [float]
putStrLn $ show $ typeOf values
You can use the hint package, or plugins. I'll show you the former (partly because my Windows installation is clearly a little broken in that cabal doesn't share my belief that I have C installed, so cabal install plugins fails).
String -> Function is easy:
import Language.Haskell.Interpreter
getF :: String -> IO (Either InterpreterError (Float -> Float))
getF xs = runInterpreter $ do
setImports ["Prelude"]
interpret xs (as :: Float -> Float)
You may want to add additional modules to the imports list. This tests out as
ghci> getF "sin" >>= \(Right f) -> print $ f (3.1415927/2)
1.0
ghci> getF "(\\x -> if x > 5.0 then 5.0 else x)" >>= \(Right f) -> print $ f 7
5.0
(Notice the escaping of the escape character \.)
Error messages
As you may have noticed, the result is wrapped in the Either data type. Right f is correct output, whereas Left err gives an InterpreterError message, which is quite helpful:
ghci> getF "sinhh" >>= \(Left err) -> print err
WontCompile [GhcError {errMsg = "Not in scope: `sinhh'\nPerhaps you meant `sinh' (imported from Prelude)"}]
Example toy program
Of course, you can use either with your code to deal with this. Let's make a fake example respond. Your real one will contain all the maths of your program.
respond :: (Float -> Float) -> IO ()
respond f = do
-- insert cunning numerical method instead of
let result = f 5
print result
A simple, one-try, unhelpful version of your program could then be
main =
putStrLn "Enter your function please:"
>> getLine
>>= getF
>>= either print respond
Example sessions
ghci> main
Enter your function please:
\x -> x^2 + 4
29.0
ghci> main
Enter your function please:
ln
WontCompile [GhcError {errMsg = "Not in scope: `ln'"}]
It does type checking for you:
ghci> main
Enter your function please:
(:"yo")
WontCompile [GhcError {errMsg = "Couldn't match expected type `GHC.Types.Float'\n with actual type `GHC.Types.Char'"}]