I have this code
module Main where
import System.Eval.Haskell
test = "a"
main :: IO ()
main = do
putStrLn "Hello, Haskell!"
i <- eval "1 + 6 :: Int" [] :: IO (Maybe Int)
when (isJust i) $ putStrLn (show (fromJust i))
putStrLn test
I run "cabal run -v"
Result:
this build was affected by the following (project) config files:
Up to date
creating /home/n0lim/HaskellProjects/TrophicModels/dist-newstyle/build
creating /home/n0lim/HaskellProjects/TrophicModels/dist-newstyle/tmp
Selecting TrophicModels-0.1.0-inplace-TrophicModels to supply
TrophicModels
/home/n0lim/HaskellProjects/TrophicModels/dist-newstyle/build/x86_64-linux/ghc-8.10.5/TrophicModels-0.1.0/x/TrophicModels/build/TrophicModels/TrophicModels
Hello, Haskell!
< command line >: cannot satisfy -package plugins
(use -v for more information)
a
Which -v was implied and what is wrong with eval?
I'm just starting to learn haskell and i dont really understand how to use files i created with an ordinary editor in the GHCi interpreter...
This is my file list-comprehension.hs
main = do
let substantive = [" Student", " Professor", " Tutor"]
let adjektive = ["fauler", "fleissiger", "hilfreicher"]
let tupel = [a ++ s | a <- adjektive, s <- substantive]
return (tupel)
When I load the file in GHCi it works alright, but then I cant actually use it. So when I try to execute tupel, it wont work.
Prelude> :load list-comprehension.hs
[1 of 1] Compiling Main ( list-comprehension.hs, interpreted )
Ok, modules loaded: Main.
*Main> tupel
<interactive>:3:1: error: Variable not in scope: tupel
This also happens when I try to get the other variables.
I have researched this a lot, but I cant find out whats wrong with my file or how this generally works...
I'm not at all sure about the "main = do" and the "return" part, but this is the only beginning and end that doesnt produce a parse error when loading .
GHCi only has the top level definitons from a file in scope. Try this:
main :: IO ()
main = print tupel
substantive :: [String]
substantive = [" Student", " Professor", " Tutor"]
adjektive :: [String]
adjektive = ["fauler", "fleissiger", "hilfreicher"]
tupel :: [String]
tupel = [a ++ s | a <- adjektive, s <- substantive]
Here is my new main with the error: parse error on input '->'
I commented where the error is. Could it be an indentation error somewhere?
main :: IO()
main = do
expression <- evaluate_input
putStrLn $ show $ compute expression
evaluate_input :: IO ()
evaluate_input = do
args <- getArgs
case args of
a:s -> return a
-> do putStrLn "Enter Expression or 'end' to exit calculator"
hFlush stdout
getLine
unless (expression -> "end") $ showExpr expression --error here
where
showExpr expression = do putStrLn $ evaluateExpr expression
evaluate_input
evaluateExpr :: String -> String
evaluateExpr = show
Few problems with your code
until is not used correctly. I find it better to recurse when I have to repeat same action again and again. You can write the monadic version of until and use that.
It is better to use getArgs inside main once. You don't need to repeat it every time.
A corrected version is here. I haven't implemented all the functions so you still need to do the hard work of parsing and evaluating expressions.
import Control.Monad (unless)
main :: IO ()
main = evaluate
evaluate :: IO ()
evaluate = do
putStrLn "Enter Expression"
expr <- getLine
unless (expr == "end") $ showExpr expr
where
showExpr expr = do putStrLn $ evaluateExpr expr
evaluate
evaluateExpr :: String -> String
evaluateExpr = show
I'm trying to learn Haskell, but the small bit of sample code I tried to write is running into a fairly large amount of "Couldn't match expected type" errors. Can anyone give me some guidance as to what I'm doing wrong/how I should go about this?
These are the errors, but I'm not really sure how I should be writing my code.
toDoSchedulerSimple.hs:6:14:
Couldn't match expected type `[t0]' with actual type `IO String'
In the return type of a call of `readFile'
In a stmt of a 'do' block: f <- readFile inFile
In the expression:
do { f <- readFile inFile;
lines f }
toDoSchedulerSimple.hs:27:9:
Couldn't match expected type `[a0]' with actual type `IO ()'
In the return type of a call of `putStr'
In a stmt of a 'do' block: putStr "Enter task name: "
In the expression:
do { putStr "Enter task name: ";
task <- getLine;
return inFileArray : task }
toDoSchedulerSimple.hs:34:9:
Couldn't match expected type `IO ()' with actual type `[a0]'
In a stmt of a 'do' block:
putStrLn "Your task is: " ++ (inFileArray !! i)
In the expression:
do { i <- randomRIO (0, (length inFileArray - 1));
putStrLn "Your task is: " ++ (inFileArray !! i) }
In an equation for `getTask':
getTask inFileArray
= do { i <- randomRIO (0, (length inFileArray - 1));
putStrLn "Your task is: " ++ (inFileArray !! i) }
toDoSchedulerSimple.hs:41:9:
Couldn't match expected type `[a0]' with actual type `IO ()'
In the return type of a call of `putStr'
In a stmt of a 'do' block:
putStr "Enter the task you would like to end: "
In the expression:
do { putStr "Enter the task you would like to end: ";
task <- getLine;
filter (endTaskCheck task) inFileArray }
toDoSchedulerSimple.hs:60:53:
Couldn't match expected type `IO ()'
with actual type `[String] -> IO ()'
In a stmt of a 'do' block: schedulerSimpleMain
In the expression:
do { (getTask inFileArray);
schedulerSimpleMain }
In a case alternative:
"get-task"
-> do { (getTask inFileArray);
schedulerSimpleMain }
This is the code itself. I think it's fairly straightforward, but the idea is to run a loop, take input, and perform actions based off of it by calling other functions.
import System.Random (randomRIO)
import Data.List (lines)
initializeFile :: [char] -> [String]
initializeFile inFile =
do f <- readFile inFile
let parsedFile = lines f
return parsedFile
displayHelp :: IO()
displayHelp =
do putStrLn "Welcome to To Do Scheduler Simple, written in Haskell."
putStrLn "Here are some commands you might find useful:"
putStrLn " 'help' : Display this menu."
putStrLn " 'quit' : Exit the program."
putStrLn " 'new-task' : Create a new task."
putStrLn " 'get-task' : Randomly select a task."
putStrLn " 'end-task' : Mark a task as finished."
putStrLn " 'view-tasks' : View all of your tasks."
quit :: IO()
quit =
do putStrLn "We're very sad to see you go...:("
putStrLn "Come back soon!"
createTask :: [String] -> [String]
createTask inFileArray =
do putStr "Enter task name: "
task <- getLine
return inFileArray:task
getTask :: [String] -> IO()
getTask inFileArray =
do i <- randomRIO (0, (length inFileArray - 1))
putStrLn "Your task is: " ++ (inFileArray !! i)
endTaskCheck :: String -> String -> Bool
endTaskCheck str1 str2 = str1 /= str2
endTask :: [String] -> [String]
endTask inFileArray =
do putStr "Enter the task you would like to end: "
task <- getLine
return filter (endTaskCheck task) inFileArray
viewTasks :: [String] -> IO()
viewTasks inFileArray =
case inFileArray of
[] -> do putStrLn "\nEnd of tasks."
_ -> do putStrLn (head inFileArray)
viewTasks (tail inFileArray)
schedulerSimpleMain :: [String] -> IO()
schedulerSimpleMain inFileArray =
do putStr "SchedulerSimple> "
input <- getLine
case input of
"help" -> displayHelp
"quit" -> quit
"new-task" -> schedulerSimpleMain (createTask inFileArray)
"get-task" -> do (getTask inFileArray); schedulerSimpleMain
"end-task" -> schedulerSimpleMain (endTask inFileArray)
"view-tasks" -> do (viewTasks inFileArray); schedulerSimpleMain
_ -> do putStrLn "Invalid input."; schedulerSimpleMain
main :: IO()
main =
do putStr "What is the name of the schedule? "
sName <- getLine
schedulerSimpleMain (initializeFile sName)
Thanks, and apologies if this isn't the correct place to be asking such a question.
There are several issues with your code, which require varying levels of work to fix. In the order that I discovered them, you have...
Incorrect Types
Lots of your type signatures are incorrect. If a function does any I/O at all, it needs to wrap its return type in IO. For example, instead of
createTask :: [String] -> [String]
you need to have
createTask :: [String] -> IO [String]
which reflects the fact that createTask does I/O (it asks the user for the name of a task).
Fortunately, the fix for this is easy - just delete all your type signatures! This sounds crazy, but it can be very helpful. GHC has a powerful type inference mechanism, which means that types can often be inferred without you specifying them explicitly. In your program, all the types are simple enough to be inferred, so you can delete all your type signatures, load the module in GHCi and type e.g. :t createTask, whereupon the interpreter will tell you the inferred type (which you can then add to the source).
Operator Precedence Issues
In Haskell, function application has the tightest binding. In particular, when you write
putStrLn "Your task is: " ++ (inFileArray !! i)
this is parsed by Haskell as
(putStrLn "Your task is: ") ++ (inFileArray !! i)
which doesn't type check, since the left hand side is of type IO () and the right-hand side is of type String. This is also easy to fix. You simply need to write what you intend, which is either
putStrLn ("Your task is: " ++ (inFileArray !! i))
or
putStrLn $ "Your task is: " ++ (inFileArray !! i)
where the operator $ means "function application with the lowest possible precedence", and is often used to avoid parentheses.
Incorrect List Concatenation
After adding parentheses, your code has the line
return (inFileArray:task)
where inFileArray is of type [String] and task is of type String. Presumably you intend to add task to the end of inFileArray.
The : operator is for adding a single item to the front of a list (an O(1) operation). You can't use it to add items to the end of a list (an O(n) operation). All lists in Haskell are linked lists, so adding an item to the front of the list is fundamentally different to adding it to the end. You want either
return (task:inFileArray)
which will add the task to the front of the list, or
return (inFileArray ++ [task])
which creates a new single-element list from task and uses the list concatenation operator ++ to add it to the end of the list.
Misunderstanding do notation and >>=
This is the most fundamental misunderstanding in your code, and will require the most work to explain. Let's look at the following (highly edited) code snippet:
schedulerSimpleMain :: [String] -> IO () -- 1
schedulerSimpleMain inFileArray = -- 2
do input <- getLine -- 3
case input of -- 4
"new-task" -> schedulerSimpleMain (createTask inFileArray) -- 5
_ -> do putStrLn "Invalid input."; schedulerSimpleMain -- 6
We already know that the type of createTask is [String] -> IO [String]. Therefore line 5 doesn't type check. The function schedulerSimpleMain expects a [String] but you are passing it an IO [String].
What you need to do is unwrap the IO layer from the result of createTask inFileArray, and pass the resulting [String] to schedulerSimpleMain (which re-wraps it in the IO layer). This is exactly what the operator >>= (pronounced bind) does. You can write this line as
createTask inFileArray >>= schedulerSimpleMain
where you can think of the >>= operator as "piping forward" the result (a bit like the Unix pipe operator) but also doing all the necessary unwrapping/rewrapping on the way.
It can be a bit tricky to use the bind operator correctly when you're just starting out, which is one of the reasons we're provided with do notation in the first place. You can write this snippet as
do newInFileArray <- createTask inFileArray
schedulerSimpleMain newInFileArray
which is simply syntactic sugar for the code I wrote above, but is a bit more readable if you're not comfortable with the bind operator.
In line 6, you have a different but related problem. The sequencing operator ; essentially means "do the computation on the left, ignore the result, then do the computation on the right". It requires the left computation to have the type IO a and the right computation to have the type IO b (for any a and b).
Unfortunately, your right computation has the type of [String] -> IO [String], so again this line doesn't typecheck. To correct it, you just need to make sure you feed the appropriate argument to schedulerSimpleMain:
do putStrLn "Invalid input."; schedulerSimpleMain inFileArray
which now typechecks. You have this kind of error all over your code. I'm not going to detail all of the fixes for you here. I think you should try and fix it yourself first. If you're still running into problems in a day or so, I can put the corrected code on hpaste for you to study.
I suggest you to break your program in smaller bits and test them one by one.
I've fixed a couple of your functions: you can do similarly for the others.
import System.Random (randomRIO)
import Data.List (lines)
-- ERROR
-- f.hs:6:14:
-- Couldn't match expected type `[t0]' with actual type `IO String'
-- In the return type of a call of `readFile'
-- In a stmt of a 'do' block: f <- readFile inFile
-- In the expression:
-- do { f <- readFile inFile;
-- let parsedFile = lines f;
-- return parsedFile }
-- WHY?
-- initializeFile reads a file, therefore it must live inside the IO monad
initializeFile :: String -> IO [String]
initializeFile inFile = do
f <- readFile inFile
let parsedFile = lines f
return parsedFile
quit :: IO()
quit = do
putStrLn "We're very sad to see you go...:("
putStrLn "Come back soon!"
-- ERROR
-- f.hs:76:44:
-- Couldn't match expected type `IO ()'
-- with actual type `[String] -> IO ()'
-- In a stmt of a 'do' block: schedulerSimpleMain
-- In the expression:
-- do { putStrLn "Invalid input.";
-- schedulerSimpleMain }
-- In a case alternative:
-- _ -> do { putStrLn "Invalid input.";
-- schedulerSimpleMain }
-- WHY?
-- in the "_" case, schedulerSimpleMain is called without parameters, but
-- it needs a [String] one.
schedulerSimpleMain :: [String] -> IO()
schedulerSimpleMain inFileArray = do
putStr "SchedulerSimple> "
input <- getLine
case input of
"quit" -> quit
_ -> do putStrLn "Invalid input."; schedulerSimpleMain inFileArray
main :: IO()
main = do
putStr "What is the name of the schedule? "
sName <- getLine
-- Extract the lines from the IO monad
ls <- initializeFile sName
-- Feed them to the scheduler
schedulerSimpleMain ls
I am trying to parse a simple binary file in Haskell with the Data.Binary.Get monad.
A simplified version of my code looks like this:
data MsgString = Definition_msg {
msg_no :: Word16
} deriving (Show)
parseDef :: Get MsgString
parseDef = do
msg_no <- getWord16le
return $ Definition_msg msg_no
parseMain :: Get [MsgString]
parseMain = do
bit <- getWord8
msg <- parseDef
return msg:parseMain
And the error I get is the following:
Prelude> :l example.hs
[1 of 1] Compiling Main ( example.hs, interpreted )
example.hs:23:17:
Couldn't match expected type `[m MsgString]'
against inferred type `Get [MsgString]'
In the second argument of `(:)', namely `parseMain'
In the expression: return msg : parseMain
In the expression:
do { bit <- getWord8;
msg <- parseDef;
return msg : parseMain }
Failed, modules loaded: none.
Can anyone see what I do wrong?
Thanks!
The issue is your last line, which parses as:
(return msg) : parseMain
But that really isn't the only problem. parseMain is of type Get [MsgString] when you really just want a [MsgString] so you must run the monadic action first:
parseMain :: Get [MsgString]
parseMain = do
bit <- getWord8
msg <- parseDef
rest <- parseMain
return (msg : rest)
Notice this will get an infinite list of MsgString's and won't terminate without an exception. Perhaps you intended to have an if statement guarding that recursive call to parseMain?