I'm trying a program from this tutorial. The program goes like this:
type Name = String
type PriceInCents = Int
type ShoppingListItem = (Name, PriceInCents)
type ShoppingList = [ShoppingListItem]
shoppingList :: ShoppingList
shoppingList = [ ("Bananas", 300)
, ("Chocolate", 250)
, ("Milk", 300)
, ("Apples", 450)
]
sumShoppingList :: ShoppingList -> PriceInCents
sumShoppingList [] = 0
sumShoppingList (x:xs) = getPriceFromItem x
+ sumShoppingList xs
getPriceFromItem :: ShoppingListItem -> PriceInCents
getPriceFromItem (_, price) = price
main :: IO ()
main = putStrLn ("Price of shopping list is "
++ show (sumShoppingList shoppingList)
++ " cents.")
I tried running it and there were no errors but I don't know what to input. I tried but I guess I got it wrong since I got this error:
ERROR - Undefined data constructor
Can anyone tell me what I should input?
The program, as it's written, doesn't take any input. Compiling with ghc will produce a working executable. Alternatively, running with runhaskell should work just as well.
I suspect, based on your question, that you're running inside the ghci interpreter. In this case, you can load a file using :l filename.hs (or :r to reload) and then run your main function by simply invoking main.
Related
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]
I literally started learning haskell in the past few hours following this tutorial. I keep getting Couldn't match type error when trying to compile the following code:
module Main where
import Control.Monad
main = do
putStrLn "Enter child age"
input <- getLine
-- convert the string to int
let age = read input :: Int
unless (age == 0) $ do
-- let ages = []
-- print age
-- add child age to list here?
ages ++ [age]
main
Here is the error:
Couldn't match type `IO' with `[]'
Expected type: [()]
Actual type: IO ()
I have been searching for several hours trying to understand the issue but have no clue. Why does ages ++ [age2] expects a type IO Int ? and how to resolve this issue?
update: ages is a list which will contain the age of both child. It will be used in future. Also created the loop
ages ++ [age1] and ages ++ [age2] are expressions that result in [Int]. They don’t modify ages; ages is just a value. Since you’re not using ages at all, a really simple fix would just be to take all three lines out:
let ages = []
ages ++ [age1]
ages ++ [age2]
ages can be built from age1 and age2 later if you were going to use it as [age1, age2]. If you were wanting to use a list to not repeat yourself, you’d probably do it more along these lines in Haskell:
readAge :: String -> IO Int
readAge prompt = do
putStrLn prompt
readLn :: IO Int
main = do
ages <- mapM readAge ["Enter child 1 age", "Enter child 2 age"]
print ages
To do it in a loop, you could start with:
readAges :: IO [Int]
readAges = do
putStrLn "Enter child age"
age <- readLn :: IO Int
if age == 0 then
return []
else
fmap (age:) readAges
main :: IO ()
main = do
ages <- readAges
print ages
where fmap (age:) readAges is short for:
ages <- readAges
return $ age : ages
In Haskell, variables are immutable. You might be looking for something more like this:
inputAges :: [Int] -> IO [Int]
inputAges (0:otherAges) = return otherAges
inputAges ages = _
This recursive function keeps track of the ages in its argument. The first line of the definition checks to see if the latest age read is 0. If so, it gives you back everything but the 0. A list will match the pattern (0:otherAges) if it has at least one element and its head is 0. If it matches, the tail is bound to otherAges. Otherwise, it goes to the next pattern (here, the next line).
I left the recursive case to be filled in, but I can give some more help on that. You need something that reads in an age and calls itself with a list that has the new age prepended. The reading in part will look much the same as it does in the code in your question.
I have a main like the following:
main :: IO ()
main = do
args <- getArgs
putStrLn $ functionName args
where
functionName args = "problem" ++ (filter (/= '"') $ show (args!!0))
Instead of putting the name to stdout like I do it right now, I want to call the function.
I am aware of the fact, that I could use hint (as mentioned in Haskell: how to evaluate a String like "1+2") but I think that would be pretty overkill for just getting that simple function name.
At the current stage it does not matter if the program crashes if the function does not exist!
Without taking special measures to preserve them, the names of functions will likely be gone completely in a compiled Haskell program.
I would suggest just making a big top-level map:
import Data.Map ( Map )
import qualified Data.Map as Map
functions :: Map String (IO ())
functions = Map.fromList [("problem1", problem1), ...]
call :: String -> IO ()
call name =
case Map.lookup name of
Nothing -> fail $ name + " not found"
Just m -> m
main :: IO ()
main = do
args <- getArgs
call $ functionName args
where
functionName args = "problem" ++ (filter (/= '"') $ show (args!!0))
If you're going to do this, you have a few approaches, but the easiest by far is to just pattern match on it
This method requires that all of your functions you want to call have the same type signature:
problem1 :: Int
problem1 = 1
problem2 :: Int
problem2 = 2
runFunc :: String -> Maybe Int
runFunc "problem1" = Just problem1
runFunc "problem2" = Just problem2
runFunc _ = Nothing
main = do
args <- getArgs
putStrLn $ runFunc $ functionName args
This requires you to add a line to runFunc each time you add a new problemN, but that's pretty manageable.
You can't get a string representation of an identifier, not without fancy non-standard features, because that information isn't retained after compilation. As such, you're going to have to write down those function names as string constants somewhere.
If the function definitions are all in one file anyway, what I would suggest is to use data types and lambdas to avoid having to duplicate those function names altogether:
Data Problem = {
problemName :: String,
evalProblem :: IO () # Or whatever your problem function signatures are
}
problems = [Problem]
problems = [
Problem {
problemName = "problem1",
evalProblem = do ... # Insert code here
},
Problem
problemName = "problem2",
evalProblem = do ... # Insert code here
}
]
main :: IO ()
main = do
args <- getArgs
case find (\x -> problemName x == (args!!0)) problems of
Just x -> evalProblem x
Nothing -> # Handle error
Edit: Just to clarify, I'd say the important takeaway here is that you have an XY Problem.
I'm trying to use the interact function, but I'm having an issue with the following code:
main::IO()
main = interact test
test :: String -> String
test [] = show 0
test a = show 3
I'm using EclipseFP and taking one input it seems like there is an error. Trying to run main again leads to a:
*** Exception: <stdin>: hGetContents: illegal operation (handle is closed)
I'm not sure why this is not working, the type of test is String -> String and show is Show a => a -> String, so it seems like it should be a valid input for interact.
EDIT/UPDATE
I've tried the following and it works fine. How does the use of unlines and lines cause interact to work as expected?
main::IO()
main = interact respondPalindromes
respondPalindromes :: String -> String
respondPalindromes =
unlines .
map (\xs -> if isPal xs then "palindrome" else "not a palindrome") .
lines
isPal :: String -> Bool
isPal xs = xs == reverse xs
GHCi and Unsafe I/O
You can reduce this problem (the exception) to:
main = getContents >> return ()
(interact calls getContents)
The problem is that stdin (getContents is really hGetContents stdin) remains evaluated in GHCi in-between calls to main. If you look up stdin, it's implemented as:
stdin :: Handle
stdin = unsafePerformIO $ ...
To see why this is a problem, you could load this into GHCi:
import System.IO.Unsafe
f :: ()
f = unsafePerformIO $ putStrLn "Hi!"
Then, in GHCi:
*Main> f
Hi!
()
*Main> f
()
Since we've used unsafePerformIO and told the compiler that f is a pure function, it thinks it doesn't need to evaluate it a second time. In the case of stdin, all of the initialization on the handle isn't run a second time and it's still in a semi-closed state (which hGetContents puts it in), which causes the exception. So I think that GHCi is "correct" in this case and the problem lies in the definition of stdin which is a practical convenience for compiled programs that will just evaluate stdin once.
Interact and Lazy I/O
As for why interact quits after a single line of input while the unlines . lines version continues, let's try reducing that as well:
main :: IO ()
main = interact (const "response\n")
If you test the above version, interact won't even wait for input before printing response. Why? Here's the source for interact (in GHC):
interact f = do s <- getContents
putStr (f s)
getContents is lazy I/O, and since f in this case doesn't need s, nothing is read from stdin.
If you change your test program to:
main :: IO ()
main = interact test
test :: String -> String
test [] = show 0
test a = show a
you should notice different behavior. And that suggests that in your original version (test a = show 3), the compiler is smart enough to realize that it only needs enough input to determine if the string read is empty or not (because if it's not empty, it doesn't need to know what a is, it just needs to print "3"). Since the input is presumably line-buffered on a terminal, it reads up until you press the return key.
I just start learning Template Haskell, and stuck on simple problem with splicing.
In one module I've implemented function tupleN which replies N-th element of the tuple:
tupleN :: Lift a => a -> Int -> Q Exp
tupleN a n = do
(TupE as) <- lift a
return $ as !! n
In the Main module I have:
main :: IO ()
main = do
let tup = (1::Int,'a',"hello")
putStrLn $ show $(tupleN $tup 1)
This seems to be working, but it wouldn't. Compiler prints error:
GHC stage restriction: `tup'
is used in a top-level splice or annotation,
and must be imported, not defined locally
In the expression: tup
In the first argument of `tupleN', namely `$tup'
In the expression: tupleN ($tup) 1
If I put tuple description right into spliced expression, code become working:
main :: IO ()
main = do
putStrLn $ show $(tupleN (1::Int,'a',"hello") 1)
What I missing with the first variant?
You've tried to use tup as a splice, but tup is just an ordinary value. You don't want to prefix it with a $.
Moreover, as the compile error states, since Template Haskell runs during the compilation process, GHC really needs to know what it's doing before it has finished compiling the current module. That means your splice expression can't depend on tup, because that's still being compiled. Inside splices, you can only use literals, imported values, and the special 'name and ''TypeName forms (which you can think of as a sort of literal, I suppose). You can get at some of the information from this compilation by using e.g. reify, but even that can only give you data that's available at compile time – if you want a function you can pass user input, or data constructed from user input, to, that's just impossible.
In short, you can't do exactly what you want to do using Template Haskell. You could, however, define a splice that expands to a function to get the ith element of a tuple of size sz:
import Control.Monad (unless)
import Language.Haskell.TH
tupleN :: Int -> Int -> Q Exp
tupleN sz i = do
unless (i < sz) . reportError $ "tupleN: index " ++ show i
++ " out of bounds for " ++ show sz ++ "-tuple"
lamE
[tupP (replicate i wildP
++ [varP (mkName "x")]
++ replicate (sz - i - 1) wildP)]
(varE (mkName "x"))