Undefined Variable, Haskell - haskell

I've got a quick question. Haskell is throwing the 57 - Undefined variable "f" error at me and I've no idea why. I'd appreciate it if you could have a look at this.
Code:
eval :: Expr -> Environment -> Float
eval expr env = eval' expr
where
eval' :: Expr-> Float
eval' (Num num) = num
eval' (App app exprs) = foldl1 (f) (map eval' exprs) -- **Line 57**
eval' (Id id) = 5
where
f = getFunctionForApp app -- **f is here**
getFunctionForApp :: String -> (Float->Float->Float)
getFunctionForApp "+" = (+)
getFunctionForApp "-" = (-)
getFunctionForApp "*" = (*)
getFunctionForApp "/" = (/)
getIdVal :: String -> Environment -> Float
getIdVal id ((curId, val):envrs)
|curId == id = val
| otherwise = getIdVal id envrs
Type definition:
data Expr = Num Float | Id String | App String [ Expr ]
deriving (Eq, Ord, Show)
type Environment = [ ( String, Float ) ]

The where block applies only to the case directly before it, not to all cases of the eval' function. So f is defined (but not used) in eval' (Id id) = 5, but it's not in scope in line 57. To fix this you need to move the where block directly after line 57.

Exactly what sepp2k said. In this case, though, I'd prefer simply swapping lines 57 and 58, so the where is attached to the right equation without splitting the equations for eval', that's more readable.
Or don't use f at all, make it
eval' (App app exprs) = foldl1 (getFunctionOrApp app) (map eval' exprs)
eval' (Id id) = 5
getFunctionOrApp :: String -> (Float -> Float -> Float)
getFunctionOrApp "+" = ...
Moving getFunctionOrApp (and getIdVal) to the same-level where as eval', it may even be reasonable to define them at the top level.

Related

Evaluating a string of operations but code does not work

I need to write a code that evaluates a string of operations and outputs the resulting integer of that string. I wrote something but it's not working and would like some help. I need to use fold since it is easier but I'm sure what's wrong. This is on Haskell and using Emacs.
evalExpr :: String -> Int
evalExpr xs = foldl 0 xs where
f v x | x == "+" = (+) v
| x == "-" = (-) v
| x == " " = 0
| otherwise = read v :: Int
For example:
evalExpr "2+4+5-8"
the output should be: 3
evalExpr ""
the output should be: 0
This is because it should read the string left to right.
You can do as #5ndG suggested. However, to evaluate a string of operations, using parsec is a better way. Here is an example for your case:
module EvalExpr where
-- You need parsec to do parsing work, and the following are just example
-- modes for your simple case.
import Text.Parsec
import Text.Parsec.Char
import Text.Parsec.String
-- A data structure for your simple arithmetic expresssion
data Expr = Lit Int
| Plus Expr Expr
| Minus Expr Expr
deriving Show
-- Evaluate an Expr to an integer number
eval :: Expr -> Int
eval (Lit n) = n
eval (Plus e1 e2) = eval e1 + eval e2
eval (Minus e1 e2) = eval e1 - eval e2
-- The following do the parsing work
-- Parser for an integer number
int :: Parser Expr
int = Lit . read <$> (many1 digit <* spaces) -- A number may be followed by spaces
-- Parser for operators "Plus" and "Minus"
plus, minus :: Parser (Expr -> Expr -> Expr)
plus = Plus <$ char '+' <* spaces
minus = Minus <$ char '-' <* spaces
-- Parser for Expr
expr :: Parser Expr
expr = chainl int (plus <|> minus) (Lit 0)
-- Evalute string to an integer
evalExpr :: String -> Int
evalExpr s = case parse expr "" s of
Left err -> error $ show err
Right e -> eval e
The above is just an simple example of using parsec. If your actual case is more complex, you'll need more work to do. So learning to use parsec is necessary. The intro_to_parsing is a good start. Also in the package description are there some learning resources.
By the way, Text.Parsec.Expr in parsec can parse an expression more conveniently, but above all, you need to know the basic of parsec.
Happy learning!
You're not far off something that works on your examples. Try this:
evalExpr :: String -> Int
evalExpr xs = foldl f (0 +) xs 0
f :: (Int -> Int) -> Char -> (Int -> Int)
f v ch | ch == '+' = (v 0 +)
| ch == '-' = (v 0 -)
| ch == ' ' = v
| otherwise = (v (read [ch] :: Int) +)
So the main difference to yours is that the accumulator in the fold is a function that takes in one Int and produces one Int, instead of just being an Int.

interpret Parigot's lambda-mu calculus in Haskell

One can interpret the lambda calculus in Haskell:
data Expr = Var String | Lam String Expr | App Expr Expr
data Value a = V a | F (Value a -> Value a)
interpret :: [(String, Value a)] -> Expr -> Value a
interpret env (Var x) = case lookup x env of
Nothing -> error "undefined variable"
Just v -> v
interpret env (Lam x e) = F (\v -> interpret ((x, v):env) e)
interpret env (App e1 e2) = case interpret env e1 of
V _ -> error "not a function"
F f -> f (interpret env e2)
How could the above interpreter be extended to the lambda-mu calculus? My guess is that it should use continuations for interpreting the additional constructs in this calculus. (15) and (16) from the Bernardi&Moortgat paper are the kind of translations I expect.
It is possible since Haskell is Turing-complete, but how?
Hint: See the comment on page 197 on this research paper for the intuitive meaning of the mu binder.
Here's a mindless transliteration of the reduction rules from the paper, using #user2407038's representation (as you'll see, when I say mindless, I really do mean mindless):
{-# LANGUAGE DataKinds, KindSignatures, GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
import Control.Monad.Writer
import Control.Applicative
import Data.Monoid
data TermType = Named | Unnamed
type Var = String
type MuVar = String
data Expr (n :: TermType) where
Var :: Var -> Expr Unnamed
Lam :: Var -> Expr Unnamed -> Expr Unnamed
App :: Expr Unnamed -> Expr Unnamed -> Expr Unnamed
Freeze :: MuVar -> Expr Unnamed -> Expr Named
Mu :: MuVar -> Expr Named -> Expr Unnamed
deriving instance Show (Expr n)
substU :: Var -> Expr Unnamed -> Expr n -> Expr n
substU x e = go
where
go :: Expr n -> Expr n
go (Var y) = if y == x then e else Var y
go (Lam y e) = Lam y $ if y == x then e else go e
go (App f e) = App (go f) (go e)
go (Freeze alpha e) = Freeze alpha (go e)
go (Mu alpha u) = Mu alpha (go u)
renameN :: MuVar -> MuVar -> Expr n -> Expr n
renameN beta alpha = go
where
go :: Expr n -> Expr n
go (Var x) = Var x
go (Lam x e) = Lam x (go e)
go (App f e) = App (go f) (go e)
go (Freeze gamma e) = Freeze (if gamma == beta then alpha else gamma) (go e)
go (Mu gamma u) = Mu gamma $ if gamma == beta then u else go u
appN :: MuVar -> Expr Unnamed -> Expr n -> Expr n
appN beta v = go
where
go :: Expr n -> Expr n
go (Var x) = Var x
go (Lam x e) = Lam x (go e)
go (App f e) = App (go f) (go e)
go (Freeze alpha w) = Freeze alpha $ if alpha == beta then App (go w) v else go w
go (Mu alpha u) = Mu alpha $ if alpha /= beta then go u else u
reduceTo :: a -> Writer Any a
reduceTo x = tell (Any True) >> return x
reduce0 :: Expr n -> Writer Any (Expr n)
reduce0 (App (Lam x u) v) = reduceTo $ substU x v u
reduce0 (App (Mu beta u) v) = reduceTo $ Mu beta $ appN beta v u
reduce0 (Freeze alpha (Mu beta u)) = reduceTo $ renameN beta alpha u
reduce0 e = return e
reduce1 :: Expr n -> Writer Any (Expr n)
reduce1 (Var x) = return $ Var x
reduce1 (Lam x e) = reduce0 =<< (Lam x <$> reduce1 e)
reduce1 (App f e) = reduce0 =<< (App <$> reduce1 f <*> reduce1 e)
reduce1 (Freeze alpha e) = reduce0 =<< (Freeze alpha <$> reduce1 e)
reduce1 (Mu alpha u) = reduce0 =<< (Mu alpha <$> reduce1 u)
reduce :: Expr n -> Expr n
reduce e = case runWriter (reduce1 e) of
(e', Any changed) -> if changed then reduce e' else e
It "works" for the example from the paper: with
example 0 = App (App t (Var "x")) (Var "y")
where
t = Lam "x" $ Lam "y" $ Mu "delta" $ Freeze "phi" $ App (Var "x") (Var "y")
example n = App (example (n-1)) (Var ("z_" ++ show n))
I can reduce example n to the expected result:
*Main> reduce (example 10)
Mu "delta" (Freeze "phi" (App (Var "x") (Var "y")))
The reason I put scare quotes around "works" above is that I have no intuition about the λμ calculus so I don't know what it should do.
Note: this is only a partial answer since I'm not sure how to extend the interpreter.
This seems like a good use case for DataKinds. The Expr datatype is indexed on a type which is named or unnamed. The regular lambda constructs produce named terms only.
{-# LANGUAGE GADTs, DataKinds, KindSignatures #-}
data TermType = Named | Unnamed
type Var = String
type MuVar = String
data Expr (n :: TermType) where
Var :: Var -> Expr Unnamed
Lam :: Var -> Expr Unnamed -> Expr Unnamed
App :: Expr Unnamed -> Expr Unnamed -> Expr Unnamed
and the additional Mu and Name constructs can manipulate the TermType.
...
Name :: MuVar -> Expr Unnamed -> Expr Named
Mu :: MuVar -> Expr Named -> Expr Unnamed
How about something like the below. I don't have a good idea on how to traverse Value a, but at least I can see it evaluates example n into MuV.
import Data.Maybe
type Var = String
type MuVar = String
data Expr = Var Var
| Lam Var Expr
| App Expr Expr
| Mu MuVar MuVar Expr
deriving Show
data Value a = ConV a
| LamV (Value a -> Value a)
| MuV (Value a -> Value a)
type Env a = [(Var, Value a)]
type MuEnv a = [(MuVar, Value a -> Value a)]
varScopeErr :: Var -> Value a
varScopeErr v = error $ unwords ["Out of scope λ variable:", show v]
appErr :: Value a
appErr = error "Trying to apply a non-lambda"
muVarScopeErr :: MuVar -> (Value a -> Value a)
muVarScopeErr alpha = id
app :: Value a -> Value a -> Value a
app (LamV f) x = f x
app (MuV f) x = MuV $ \y -> f x `app` y
app _ _ = appErr
eval :: Env a -> MuEnv a -> Expr -> Value a
eval env menv (Var v) = fromMaybe (varScopeErr v) $ lookup v env
eval env menv (Lam v e) = LamV $ \x -> eval ((v, x):env) menv e
eval env menv (Mu alpha beta e) = MuV $ \u ->
let menv' = (alpha, (`app` u)):menv
wrap = fromMaybe (muVarScopeErr beta) $ lookup beta menv'
in wrap (eval env menv' e)
eval env menv (App f e) = eval env menv f `app` eval env menv e
example 0 = App (App t (Var "v")) (Var "w")
where
t = Lam "x" $ Lam "y" $ Mu "delta" "phi" $ App (Var "x") (Var "y")
example n = App (example (n-1)) (Var ("z_" ++ show n))

Monadic Haskell operators on custom data types (+ that carries state)

I'm following the Write Yourself a Scheme in 48 Hours tutorial and given the code below I took a little detour to be able to run things like (+ 4 4.0) (I added support for Floats):
import Control.Monad.Except
import Text.ParserCombinators.Parsec hiding (spaces)
data LispError = NumArgs Integer [LispVal]
| TypeMismatch String LispVal
| Parser ParseError
| BadSpecialForm String LispVal
| NotFunction String String
| UnboundVar String String
| Default String
type ThrowsError = Either LispError
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
| Number Integer
| Float Float
| String String
| Bool Bool
instance Show LispVal where
show = showVal
instance Show LispError where
show = showErr
showVal :: LispVal -> String
showVal (Number x) = show x
-- ...
showErr :: LispError -> String
showErr (TypeMismatch expected found) = "Invalid type, expected: " ++ expected ++ ", found: " ++ show found
showErr (Default message) = "Error: " ++ message
-- ...
instance Num LispVal where
(Number x) + (Number y) = Number $ x + y
(Float x) + (Float y) = Float $ x + y
(Number x) + (Float y) = Float $ (fromInteger x) + y
(Float x) + (Number y) = Float $ x + (fromInteger y)
plusLispVal :: LispVal -> LispVal -> ThrowsError LispVal
(Number x) `plusLispVal` (Number y) = return . Number $ x + y
(Float x) `plusLispVal` (Float y) = return . Float $ x + y
(Number x) `plusLispVal` (Float y) = return . Float $ (fromInteger x) + y
(Float x) `plusLispVal` (Number y) = return . Float $ x + (fromInteger y)
x `plusLispVal` (Number _) = throwError $ TypeMismatch "number" x
x `plusLispVal` (Float _) = throwError $ TypeMismatch "number" x
(Number _) `plusLispVal` x = throwError $ TypeMismatch "number" x
(Float _) `plusLispVal` x = throwError $ TypeMismatch "number" x
x `plusLispVal` y = throwError $ Default $ "+ expects numbers, given: " ++ show x ++ " and " ++ show y
I'm wondering if I could somehow make the + operator equivalent to the plusLispVal function above, that is, make it monadic so I can pass the error state with it, I think this would make my code a bit cleaner and also I could benefit of subtraction (and other operations) for free.
Example:
*Main> (Number 2) + (String "asd")
*** Exception: asd.hs:(51,5)-(54,56): Non-exhaustive patterns in function +
*Main> (Number 2) `plusLispVal` (String "asd")
Left Invalid type, expected: number, found: "asd"
No. + has the type Num a => a -> a -> a, that is if your information isn't contained in one of the parameters, it can't be in the result either. What you can do is lift it: liftM2 (+) :: (Monad m, Num a) => m a -> m a -> m a, or you can introduce a function that kinda looks like + if that's what you're after (+!) = plusLispVal.
You might wanna have a lifted version of + lying around anyway because otherwise you can't chain additions (and other operations) (also, your Num instance seems to be lacking a fromIntegral implementation).
Yes, by refactoring your code so that a LispError can fit in a LispVal, perhaps by adding a constructor like so:
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
| Number Integer
| Float Float
| String String
| Bool Bool
| Error LispError
Then, you can write up a Num instance for LispVal.
Alternatively, you could write a Num instance for ThrowsError LispVal and use it like return x + return y.

How to evaluate expressions in Haskell

I understand how to create and evaluate a simple data-type Expr. For example like this:
data Expr = Lit Int | Add Expr Expr | Sub Expr Expr | [...]
eval :: Expr -> Int
eval (Lit x) = x
eval (Add x y) = eval x + eval y
eval (Sub x y) = eval x - eval y
So here is my question: How can I add Variables to this Expr type, which should be evaluated for its assigned value? It should look like this:
data Expr = Var Char | Lit Int | Add Expr Expr [...]
type Assignment = Char -> Int
eval :: Expr -> Assignment -> Int
How do I have to do my eval function now for (Var Char) and (Add Expr Expr)? I think I figured out the easiest, how to do it for Lit already.
eval (Lit x) _ = x
For (Var Char) I tried a lot, but I cant get an Int out of an Assignment.. Thought It would work like this:
eval (Var x) (varname number) = number
Well if you model your enviroment as
type Env = Char -> Int
Then all you have is
eval (Var c) env = env c
But this isn't really "correct". For one, what happens with unbound variables? So perhaps a more accurate type is
type Env = Char -> Maybe Int
emptyEnv = const Nothing
And now we can see whether a variable is unbound
eval (Var c) env = maybe handleUnboundCase id (env c)
And now we can use handleUnboundCase to do something like assign a default value, blow up the program, or make monkeys climb out of your ears.
The final question to ask is "how are variables bound?". If you where looking for a "let" statement like we have in Haskell, then we can use a trick known as HOAS (higher order abstract syntax).
data Exp = ... | Let Exp (Exp -> Exp)
The HOAS bit is that (Exp -> Exp). Essentially we use Haskell's name-binding to implement our languages. Now to evaluate a let expression we do
eval (Let val body) = body val
This let's us dodge Var and Assignment by relying on Haskell to resolve the variable name.
An example let statement in this style might be
Let 1 $ \x -> x + x
-- let x = 1 in x + x
The biggest downside here is that modelling mutability is a royal pain, but this was already the case when relying on the Assignment type vs a concrete map.
You need to apply your Assignment function to the variable name to get the Int:
eval (Var x) f = f x
This works because f :: Char -> Int and x:: Char, so you can just do f x to get an Int.
Pleasingly this will work across a collection of variable names.
Example
ass :: Assignment
ass 'a' = 1
ass 'b' = 2
meaning that
eval ((Add (Var 'a') (Var 'b')) ass
= eval (Var 'a') ass + eval (Var 'b') ass
= ass 'a' + ass 'b'
= 1 + 2
= 3
Pass the assignment functions through to other calls of eval
You need to keep passing the assignment function around until you get integers:
eval (Add x y) f = eval x f + eval y f
Different order?
If you're allowed to change the types, it seems more logical to me to put the assignment function first and the data second:
eval :: Assignment -> Expr -> Int
eval f (Var x) = f x
eval f (Add x y) = eval f x + eval f y
...but I guess you can think of it as a constant expression with varying variables (feels imperative)rather than a constant set of values across a range of expressions (feels like referential transparency).
I would recommend using Map from Data.Map instead. You could implement it something like
import Data.Map (Map)
import qualified Data.Map as M -- A lot of conflicts with Prelude
-- Used to map operations through Maybe
import Control.Monad (liftM2)
data Expr
= Var Char
| Lit Int
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
deriving (Eq, Show, Read)
type Assignment = Map Char Int
eval :: Expr -> Assignment -> Maybe Int
eval (Lit x) _ = Just x
eval (Add x y) vars = liftM2 (+) (eval x vars) (eval y vars)
eval (Sub x y) vars = liftM2 (-) (eval x vars) (eval y vars)
eval (Mul x y) vars = liftM2 (*) (eval x vars) (eval y vars)
eval (Var x) vars = M.lookup x vars
But this looks clunky, and we'd have to keep using liftM2 op every time we added an operation. Let's clean it up a bit with some helpers
(|+|), (|-|), (|*|) :: (Monad m, Num a) => m a -> m a -> m a
(|+|) = liftM2 (+)
(|-|) = liftM2 (-)
(|*|) = liftM2 (*)
infixl 6 |+|, |-|
infixl 7 |*|
eval :: Expr -> Assignment -> Maybe Int
eval (Lit x) _ = return x -- Use generic return instead of explicit Just
eval (Add x y) vars = eval x vars |+| eval y vars
eval (Sub x y) vars = eval x vars |-| eval y vars
eval (Mul x y) vars = eval x vars |*| eval y vars
eval (Var x) vars = M.lookup x vars
That's a better, but we still have to pass around the vars everywhere, this is ugly to me. Instead, we can use the ReaderT monad from the mtl package. The ReaderT monad (and the non-transformer Reader) is a very simple monad, it exposes a function ask that returns the value you pass in when it's run, where all you can do is "read" this value, and is usually used for running an application with static configuration. In this case, our "config" is an Assignment.
This is where the liftM2 operators really come in handy
-- This is a long type signature, let's make an alias
type ExprM a = ReaderT Assignment Maybe a
-- Eval still has the same signature
eval :: Expr -> Assignment -> Maybe Int
eval expr vars = runReaderT (evalM expr) vars
-- evalM is essentially our old eval function
evalM :: Expr -> ExprM Int
evalM (Lit x) = return x
evalM (Add x y) = evalM x |+| evalM y
evalM (Sub x y) = evalM x |-| evalM y
evalM (Mul x y) = evalM x |*| evalM y
evalM (Var x) = do
vars <- ask -- Get the static "configuration" that is our list of vars
lift $ M.lookup x vars
-- or just
-- evalM (Var x) = ask >>= lift . M.lookup x
The only thing that we really changed was that we have to do a bit extra whenever we encounter a Var x, and we removed the vars parameter. I think this makes evalM very elegant, since we only access the Assignment when we need it, and we don't even have to worry about failure, it's completely taken care of by the Monad instance for Maybe. There isn't a single line of error handling logic in this entire algorithm, yet it will gracefully return Nothing if a variable name is not present in the Assignment.
Also, consider if later you wanted to switch to Doubles and add division, but you also want to return an error code so you can determine if there was a divide by 0 error or a lookup error. Instead of Maybe Double, you could use Either ErrorCode Double where
data ErrorCode
= VarUndefinedError
| DivideByZeroError
deriving (Eq, Show, Read)
Then you could write this module as
data Expr
= Var Char
| Lit Double
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
| Div Expr Expr
deriving (Eq, Show, Read)
type Assignment = Map Char Double
data ErrorCode
= VarUndefinedError
| DivideByZeroError
deriving (Eq, Show, Read)
type ExprM a = ReaderT Assignment (Either ErrorCode) a
eval :: Expr -> Assignment -> Either ErrorCode Double
eval expr vars = runReaderT (evalM expr) vars
throw :: ErrorCode -> ExprM a
throw = lift . Left
evalM :: Expr -> ExprM Double
evalM (Lit x) = return x
evalM (Add x y) = evalM x |+| evalM y
evalM (Sub x y) = evalM x |-| evalM y
evalM (Mul x y) = evalM x |*| evalM y
evalM (Div x y) = do
x' <- evalM x
y' <- evalM y
if y' == 0
then throw DivideByZeroError
else return $ x' / y'
evalM (Var x) = do
vars <- ask
maybe (throw VarUndefinedError) return $ M.lookup x vars
Now we do have explicit error handling, but it isn't bad, and we've been able to use maybe to avoid explicitly matching on Just and Nothing.
This is a lot more information than you really need to solve this problem, I just wanted to present an alternative solution that uses the monadic properties of Maybe and Either to provide easy error handling and use ReaderT to clean up that noise of passing an Assignment argument around everywhere.

Haskell is throwing the 57 - Undefined variable "f" error at me

I've got a quick question. Haskell is throwing the 57 - Undefined variable "f" error at me and I've no idea why. I'd appreciate it if you could have a look at this.
Code:
eval :: Expr -> Environment -> Float
eval expr env = eval' expr
where
eval' :: Expr-> Float
eval' (Num num) = num
eval' (App app exprs) = foldl1 (f) (map eval' exprs) -- **Line 57**
eval' (Id id) = 5
where
f = getFunctionForApp app -- **f is here**
getFunctionForApp :: String -> (Float->Float->Float)
getFunctionForApp "+" = (+)
getFunctionForApp "-" = (-)
getFunctionForApp "*" = (*)
getFunctionForApp "/" = (/)
getIdVal :: String -> Environment -> Float
getIdVal id ((curId, val):envrs)
|curId == id = val
| otherwise = getIdVal id envrs
Type definition:
data Expr = Num Float | Id String | App String [ Expr ]
deriving (Eq, Ord, Show)
type Environment = [ ( String, Float ) ]
I can't really say it, but after trying to decrypt the code I guess you meant the following:
eval :: Expr -> Environment -> Float
eval expr env = eval' expr
where eval' :: Expr -> Float
eval' (Num num) = num
eval' (App app exprs) = foldl1 (f) (map eval' exprs)
where f = getFunctionForApp app -- that has to be in this line
eval' (Id id) = 5
(Now with the formatted code I'm sure that's it. where clauses only work for the line immediately before the clause)
The problem is that the inner where clause attaches to the line
eval' (Id id) = 5
but it's needed for the line above
eval' (App app exprs) = foldl1 (f) (map eval' exprs) -- **Line 57**
In general, each line of a function definition has its own scope. A where clause may refer to pattern variables from the line it's attached to, and scopes over only the remainder of that line.

Resources