I have this code snippet in Haskell:
matchEx :: Expr -> [Expr]
matchEx (Number n) = undefined
matchEx (Boolean b) = undefined
matchEx (If condStatement thenStatement elseStatement) = undefined
What would the equivalent pattern matching looks like in racket? After looking at the documentation, this is what I have. Thanks.
(define (matchEx-calls expr)
(match expr
[(literal n) ([])]
[(id ident) ([])]
[(If condStatement thenStatement elseStatement) ([])]
)
)
Here is an example to get you started:
#lang racket
(struct Expr () #:transparent)
(struct Number Expr (n) #:transparent)
(struct Boolean Expr (b) #:transparent)
(struct Or Expr (exprs) #:transparent)
(define (format-Expr e)
(define ~ format-Expr)
(match e
[(Number n) (~a n)]
[(Boolean b) (if b "true" "false")]
[(Or es) (match es
['() "true"]
[(list e) (~ e)]
[(list e1 e2) (~a (~ e1) " or " (~ e2))]
[(list e1 es ...) (~a (~ e1) " or " (~ (Or es)))])]
[(? Expr? e)
; we get here if we forgot to implement a case
(error 'format-expr (~a "internal error, got: " e))]
[_
; this on the other hand is an user error
(error 'format-expr (~a "expected an Expr, got: " e))]))
(format-Expr (Or (list (Boolean #t) (Boolean #f))))
Related
I'm writing a arithmetic parser to treat expressions like "1+2-3". I use this blog post as reference. To treat left associativity and precedence, I write a parser with Parsec according to this BNF (from blog post).
<exp> ::= <term> { ("+" | "-") <term> }
<term> ::= <factor> { ("*" | "/") <factor> }
<factor> ::= "(" <exp> ")" | <unary_op> <factor> | <int>
This is my parser code.
parseExp :: Parser Exp
parseExp = do
t1 <- parseTerm
loop t1
where termSuffix t1 = do
op <- lexeme $ oneOf "+-"
t2 <- parseTerm
case op of
'+' -> termSuffix (Binary Plus t1 t2)
'-' -> termSuffix (Binary Minus t1 t2)
loop t = termSuffix t <|> return t
parseTerm :: Parser Exp
parseTerm = do
f1 <- parseFactor
loop f1
where factorSuffix f1 = do
op <- lexeme $ oneOf "*/"
f2 <- parseFactor
case op of
'*' -> factorSuffix (Binary Mul f1 f2)
'/' -> factorSuffix (Binary Div f1 f2)
loop t = factorSuffix t <|> return t
parseFactor :: Parser Exp
parseFactor = parseConst <|> parseParen <|> parseUnary
parseParen = do
void $ lexeme $ char '('
e <- parseExp
void $ lexeme $ char ')'
return e
parseUnary :: Parser Exp
parseUnary = do
op <- lexeme $ oneOf "!~-"
f <- parseFactor
case op of
'!' -> return $ Unary LogNeg f
'~' -> return $ Unary BitCompl f
'-' -> return $ Unary ArithNeg f
parseConst :: Parser Exp
parseConst = do
i <- many1 digit
return (Const $ read i)
I also used this tutorial code as reference. tutorial
simpleExpr7 :: Parser SimpleExpr
simpleExpr7 = do
-- first parse a term
e <- term7
-- then see if it is followed by an '+ expr' suffix
maybeAddSuffix e
where
-- this function takes an expression, and parses a
-- '+ expr' suffix, returning an Add expression
-- it recursively calls itself via the maybeAddSuffix function
addSuffix e0 = do
void $ lexeme $ char '+'
e1 <- term7
maybeAddSuffix (Add e0 e1)
-- this is the wrapper for addSuffix, which adapts it so that if
-- addSuffix fails, it returns just the original expression
maybeAddSuffix e = addSuffix e <|> return e
My code doesn't work. This code works like this.
*Main CodeGen Parser> parseWithEof parseExp "-2"
Right (Unary ArithNeg (Const 2))
*Main CodeGen Parser> parseWithEof parseExp "(2)"
Right (Const 2)
*Main CodeGen Parser> parseWithEof parseExp "-!(((2)))"
Right (Unary ArithNeg (Unary LogNeg (Const 2)))
*Main CodeGen Parser> parseWithEof parseExp "1+2"
Left (line 1, column 4):
unexpected end of input
expecting digit
*Main CodeGen Parser> parseWithEof parseExp "1+2+3"
Left (line 1, column 6):
unexpected end of input
expecting digit
*Main CodeGen Parser> parseWithEof parseExp "1+2*3"
Left (line 1, column 6):
unexpected end of input
expecting digit
I can't understand why this results unexpected end of input.
Consider parsing 1+2. In parseExp this parses 1 into t1 = Const 1 and then enters the loop loop (Const 1). The loop tries the first alternative termSuffix (Const 1) which succesfully parses the operator +, the next term t2 = Const 2, and then loops back into termSuffix (Binary Plus (Const 1) (Const 2)) which expects either a + or -. The parse fails. Instead of looping back into termSuffix, you should loop back into loop to allow a single term after the first +:
parseExp :: Parser Exp
parseExp = do
t1 <- parseTerm
loop t1
where termSuffix t1 = do
op <- lexeme $ oneOf "+-"
t2 <- parseTerm
case op of
-- *** use `loop` here, not `termSuffix` ***
'+' -> loop (Binary Plus t1 t2)
'-' -> loop (Binary Minus t1 t2)
loop t = termSuffix t <|> return t
After making a similar change to parseTerm, your test cases all work fine.
I am working on a practice sheet for a final tomorow and I am a bit confused trying to figure out what the question is asking and how to resolve it. I wanted to check here and see if the good people of stack overflow can help me resolve it.
The question is set up like this:
Show a derivation tree (which is a trace of typecheck) demonstrating that the following expression has a type :
(appC (lamC ‘x ??? (plusC (idC ‘x) (numC 1)))
(numC 2) )
It is based on this definition of type check:
(define (typecheck [a : ExprC] [tenv : TypeEnv])
(type-case ExprC a
[numC (n) (numT)]
[plusC (l r) (typecheck-nums l r tenv)]
[multC (l r) (typecheck-nums l r tenv)]
[idC (n) (type-lookup n tenv)]
[lamC (n arg-type body)
(arrowT arg-type
(typecheck body
(extend-env (tbind n arg-type)
tenv)))]
[appC (fun arg)
(type-case Type (typecheck fun tenv)
[arrowT (arg-type result-type)
(if (equal? arg-type
(typecheck arg tenv))
result-type
(type-error arg
(to-string arg-type)))]
[else (type-error fun "function")])]))
(define (typecheck-nums l r tenv)
(type-case Type (typecheck l tenv)
[numT ()
(type-case Type (typecheck r tenv)
[numT () (numT)]
[else (type-error r "num")])]
[else (type-error l "num")]))
(define (type-error a msg)
(error 'typecheck (string-append
"no type: "
(string-append
(to-string a)
(string-append " not "
msg)))))
When I run this in racket :
(typecheck (appC
(lamC 'x (numT) (plusC (idC 'x) (numC 1)))
(numC 2))
mt-env)
I do get:
- Type
(numT)
- Type
(numT)
At the bottom it states :
"You check that the type for 'x must be : numT"
So it is coming up with numT but I am confused about the tracing part, I know this question is long but this is the one out of all of the practice questions that is confusing me the most. Any advice/help is appreciated
The question: "Show a derivation tree demonstrating that the following expression has a type" means that you need to make a proof that the expression has the given type.
Consider this example (unrelated to your typecheck example):
The result of evaluating the expression (+ 1 2) has type int.
Why:
The subexpression 1 has type int
The subexpression 2 has type int
The subexpression + has type int int -> int
Due to the type above the rule for application states that
applying a function of type int int -> int to two arguments of type int, has a result of type int.
A type checker examines an expression recursively. It determines the types of the subexpressions first, and then use their types to infer the types of compound expressions.
In order to get a proof that a given expression has a certain type, one can use the trace of running the type checker. To get the trace, modify typechecker to print the types as they are inferred.
Untested modification:
(define (typecheck [a : ExprC] [tenv : TypeEnv])
(define (tell result-type)
(display "The type of ")
(display a)
(display " is: ")
(display result-type)
(newline))
(tell
(type-case ExprC a
[numC (n) (numT)]
[plusC (l r) (typecheck-nums l r tenv)]
[multC (l r) (typecheck-nums l r tenv)]
[idC (n) (type-lookup n tenv)]
[lamC (n arg-type body) (arrowT arg-type
(typecheck body
(extend-env (tbind n arg-type)
tenv)))]
[appC (fun arg) (type-case Type (typecheck fun tenv)
[arrowT (arg-type result-type)
(if (equal? arg-type
(typecheck arg tenv))
result-type
(type-error arg
(to-string arg-type)))]
[else (type-error fun "function")])])))
I want to implement a method for showing a propositional formula in SML. The solutions that I found so far was of this type:
fun show (Atom a) = a
| show (Neg p) = "(~ " ^ show p ^ ")"
| show (Conj(p,q)) = "(" ^ show p ^ " & " ^ show q ^ ")"
| show (Disj(p,q)) = "(" ^ show p ^ " | " ^ show q ^ ")";
This produces unnecessary braces:
((~p) & (q | r))
when, what I'd like to have is:
~ p & (q | r)
I saw, that Haskell has a function (display?) which does this nicely. Can someone help me out a little bit. How should I go about this?
If you want to eliminate redundant parentheses, you will need to pass around some precedence information. For example, in Haskell, the showsPrec function embodies this pattern; it has type
showsPrec :: Show a => Int -> a -> String -> String
where the first Int argument is the precedence of the current printing context. The extra String argument is a trick to get efficient list appending. I'll demonstrate how to write a similar function for your type, though admittedly in Haskell (since I know that language best) and without using the extra efficiency trick.
The idea is to first build a string that has no top-level parentheses -- but does have all the parentheses needed to disambiguate subterms -- then add parentheses only if necessary. The unbracketed computation below does the first step. Then the only question is: when should we put parentheses around our term? Well, the answer to that is that things should be parenthesized when a low-precedence term is an argument to a high-precedence operator. So we need to compare the precedence of our immediate "parent" -- called dCntxt in the code below -- to the precedence of the term we're currently rendering -- called dHere in the code below. The bracket function below either adds parentheses or leaves the string alone based on the result of this comparison.
data Formula
= Atom String
| Neg Formula
| Conj Formula Formula
| Disj Formula Formula
precedence :: Formula -> Int
precedence Atom{} = 4
precedence Neg {} = 3
precedence Conj{} = 2
precedence Disj{} = 1
displayPrec :: Int -> Formula -> String
displayPrec dCntxt f = bracket unbracketed where
dHere = precedence f
recurse = displayPrec dHere
unbracketed = case f of
Atom s -> s
Neg p -> "~ " ++ recurse p
Conj p q -> recurse p ++ " & " ++ recurse q
Disj p q -> recurse p ++ " | " ++ recurse q
bracket
| dCntxt > dHere = \s -> "(" ++ s ++ ")"
| otherwise = id
display :: Formula -> String
display = displayPrec 0
Here's how it looks in action.
*Main> display (Neg (Conj (Disj (Conj (Atom "a") (Atom "b")) (Atom "c")) (Conj (Atom "d") (Atom "e"))))
"~ ((a & b | c) & d & e)"
I am trying to implement the following code in Haskell, to evaluate an Arithmetic Expression, unfortunately it give me the error Couldn't match expected type `Integer' against inferred type `Value' at (IVal (eval c x)) + (IVal (eval c (Prim IntAddOp xs)))).
Plz help me with some solution.
type Env = GenEnv Value
data Value
= IVal Integer
| BVal Bool
--------------------------------------------------
eval :: Env -> Exp -> Value
eval _ (Num n) = IVal n
eval _ (Prim IntAddOp ((Num x) : (Num y):[])) = IVal (x+y)
eval c (Prim IntAddOp (x: xs)) = IVal ((IVal (eval c x)) + (IVal (eval c
(Prim IntAddOp xs))))
Thank you...
The last line should be changed:
IVal $
case eval c x of
IVal ix ->
case eval c (Prim IntAddOp xs) of
IVal ip -> ix + ip
_ -> error "trying to add int value to bool value"
_ -> error "trying to add bool value to int value"
(Or something similar. You didn't provide all the definitions of the data structures to be sure.)
However, this can be tidied up some more. Further, you never seem to use the Env parameter.
EDIT: Here's a nicer way of doing it. Note we're working in the Maybe monad: adding a boolean value to an integer value makes no sense.
eval :: Expression -> Maybe Value
eval (Integer i) = return $ IVal i
eval (Boolean b) = return $ BVal b
eval (Add l r) =
do el <- eval l
er <- eval r
return . IVal $ l + r
eval (And l r) =
do el <- eval l
er <- eval r
return . BVal $ l && r
... and so on
If you want error messages, replace the Maybe with the error monad.
This error means exactly what it says.
First of all, what did Haskell expect?
IVal ( something )
Haskell expects something to be an Integer, because your definition of Value said it should be:
data Value
= IVal Integer
| BVal Bool
Second of all, what did Haskell infer?
(IVal (eval c x)) + (IVal (eval c (Prim IntAddOp xs)))
I have to assume you've defined a Num instance for Values, otherwise + wouldn't work. So when you add a Value to an Value, you should get an Value result. (I know that the two things being added are Values because IVal is a constructor for the Value type)
So Haskell infers that this expression has the type Value.
Why don't they match?
Haskell is expecting an Integer expression, and you gave it a Value expression. The error means exactly what it says. So how to fix it? Well, I have no clue. Taking a stab in the dark, you could remove the IVal constructors from the addition.
( (eval c x) + (eval c (Prim IntAddOp xs)) )
Wait a minute, the result of eval is a Value, not an Integer, so...we're still adding Values, and wrapping these in an IVal is even more wrong than it was before.
How about we define a function to get the Integer out of an IVal.
extract :: Value -> Integer
extract (IVal x) = x
extract (BVal True) = 1
extract (BVal False) = 0
Here I'm using the horrendous C-like convention of treating booleans as 1 or 0. You might want to leave extract undefined on BVals, or throw an error, or whatever. At least now we have a way of extracting an Integer from a Value.
So now I'm assuming that you actually don't have a Num instance for Value. Let's just extract the Integers out of those two expressions in order to add them together.
( extract (eval c x) + extract (eval c (Prim IntAddOp xs)) )
Now that should be inferred to be an Integer. So then we can wrap it in an IVal constructor.
IVal (extract (eval c x) + extract (eval c (Prim IntAddOp xs)))
Problem solved?
eval _ (Prim _ ([])) = IVal (0)
eval _ (Prim IntAddOp ((Num x) : (Num y):[])) = IVal (x+y)
eval s (Prim IntAddOp (x: xs)) = IVal (test (eval s x)+ test (eval s (Prim IntAddOp
xs)))
This works fine it is evaluating 1+2+3=...;
Thanks for you help guys.......
How can I give a general rule that includes all the expressions below?
E.g one expression, another one for sub and one for mult.
I need to use recursion but i got confused...
simplify :: Expr->Expr
simplify (Mult (Const 0)(Var"x"))
= Const 0
simplify (Mult (Var "x") (Const 0))
= Const 0
simplify (Plus (Const 0) (Var "x"))
= Var "x"
simplify (Plus (Var "x") (Const 0))
= Var "x"
simplify (Mult (Const 1) (Var"x"))
= Var "x"
simplify (Mult(Var"x") (Const 1))
= Var "x"
simplify (Minus (Var"x") (Const 0))
= Var "x"
simplify (Plus (Const x) (Const y))
= Const (x + y)
simplify (Minus (Const x) (Const y))
= Const (x - y)
simplify (Mult (Const x) (Const y))
= Const (x * y)
simplify x = x
First up: I know reasonably little about Haskell, and my total time spent programming the language is no more than 8 hours spread over 5 years or so, though I have read plenty about the language. Thus, forgive my no doubt horrible style.
I tackled this problem since it looked like an easy way to get into a little bit of Haskell programming. First up, I made a data type inspired by the sample:
data Expr = Const Int | Mult Expr Expr | Plus Expr Expr | Var String
I made it a little simpler than the original, and left out Minus, but otherwise it's the same.
I quickly found out that values constructed using e.g. "Const 4" were not printable with the above, as there was no show function applicable. I made Expr an instance of the Show type class, and provided a simple definition of show, taking operator precedence into account:
instance Show Expr where
show (Const n) = show n
show (Var n) = show n
show (Plus a b) = (show a) ++ "+" ++ (show b)
show (Mult a b) = "(" ++ (show a) ++ ") * (" ++ (show b) ++ ")"
Next up was the simplification task itself. As Glomek hints, there's an issue with trying to evaluate everything just using pattern matching in one function.
Specifically, for any given operation (all operations in the example are binary) you'd like to first simplify the left tree, then the right tree, and then simplify the current Expr based on what those subtrees evaluated to; e.g. if both simplified to Const, then you can replace the entire subtree with the evaluated operation. However, pattern matching forces you to choose what to do based on the immediate node's children, rather than what the subtrees return after being simplified themselves.
Thus, to get pattern-matching to do the job of deciding whether to evaluate the current node or not as a constant subexpression, it's important to simplify the subtrees, then dispatch based on the simplified whole.
I did this using a separate function I called eval, whose purpose is to pattern-match on things that can be reduced, assuming that subtrees have already been reduced. It also handles multiplication by 0 and 1, and addition of 0:
-- Tries to evaluate any constant expressions.
eval :: Expr -> Expr
eval (Mult (Const a) (Const b)) = Const (a * b)
eval (Mult (Const a) b)
| a == 0 = Const 0
| a == 1 = b
| otherwise = (Mult (Const a) b)
eval (Mult a (Const b))
| b == 0 = Const 0
| b == 1 = a
| otherwise = (Mult a (Const b))
eval (Plus (Const a) (Const b)) = Const (a + b)
eval (Plus (Const a) b)
| a == 0 = b
| otherwise = (Plus (Const a) b)
eval (Plus a (Const b))
| b == 0 = a
| otherwise = (Plus a (Const b))
eval e = e
Now that I have eval, and I know it's safe to call at the top level of an expression tree (i.e. it won't infinitely recurse), I can call it from simplify after I've simplified the subtrees:
-- Tries to match evaluation rules after simplifying subtrees.
simplify :: Expr -> Expr
simplify (Plus a b) = eval (Plus (simplify a) (simplify b))
simplify (Mult a b) = eval (Mult (simplify a) (simplify b))
simplify e = e
This version of simplify has many limitations: it won't distribute a multiplication over a non-Const subtree, it won't reorder the expression to bring constant expressions together (so the equivalent of 1+a+2 won't get simplified to a+3), etc. However, it gets the basic jobs done.
The recursion comes in when you need to deal with nested expressions. For instance, how do you simply (Plus (Plus 2 3) (Plus 4 5))?
One approach is to break it into two functions. Move the one level logic (which you show above) into its own function. The main simplify function might have a rule similar to the following for Plus:
simplify (Plus x y) = simplify_one_level (Plus (simplify x) (simplify y))