I can define the infix '+' as below in Racket:
(require syntax/parse/define (only-in racket (#%app racket:#%app)))
(define-syntax-parser #%app
[(_ Value1 {~datum +} Value2)
#'(+ Value1 Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)]
)
(displayln (1 + 2))
I want to add multiple infix '+' using ~between but it doesn't work:
(require syntax/parse/define (only-in racket (#%app racket:#%app)))
(define-syntax-parser #%app
[(_ {~between {Value1 {~datum +}} 1 100} Value2)
#'(+ Value1 Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)]
)
(displayln (1 + 2))
The syntax in Racket is here: https://docs.racket-lang.org/syntax/stxparse-patterns.html with ~between but no ~repeat.
How to use ~between property to repeat items in syntax?
I have a work-around but it doesn't look pure multiple infix +, need to wrap every left entry in brackets:
(require syntax/parse/define (only-in racket (#%app racket:#%app)))
(define-syntax-parser #%app
[(_ {Value1 {~datum +}} ... Value2)
#'(+ Value1 ... Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)]
)
(displayln ({1 +} {2 +} 3))
What you want is a combination of ~seq and ...+.
(define-syntax-parser #%app
[(_ {~seq Value1 {~datum +}} ...+ Value2)
#'(+ Value1 ... Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)])
The ~seq matches a sequence of things without requiring them to be grouped by brackets as your workaround did.
The ...+ is a repetition pattern to match one-or-more things, as opposed to zero-or-more. This makes sure that (f) isn't accidentally interpreted as (+ f).
One more note, when you're defining #%app directly, as opposed to defining under a different name and then renaming the export, you need to be extra careful about implicit recursive uses. For instance (+ + x) is an infinite loop. To fix that you could use racket:#%app in both outputs, like #'(racket:#%app + Value1 ... Value2).
(define-syntax-parser #%app
[(_ {~seq Value1 {~datum +}} ...+ Value2)
#'(racket:#%app + Value1 ... Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)])
Related
I'm trying to write an evaluator for my language that takes a parsed if-block, evaluates all conditions and filters out the False branches and then picks one branch to take at random. I'm at the stage wherein I can filter out the branches and be left with my possible paths but only within GHCI. When I attempt to pass an if-block into my program through the command line, what occurs is if the first branch is True, that's the only branch that is taken, otherwise an empty list is returned regardless if there are any sub-branches or not. My evaluator for binary expressions works so I know that my error is with my logic in my if evaluator or parser.
Here is the behaviour through the command line:
~/Desktop/Olivia > ./Main "if (1 > 3)-> 1 + 1 [] (1 < 2)-> 2 + 2"
[]
~/Desktop/Olivia > ./Main "if (1 < 3)-> 1 + 1 [] (1 < 2)-> 2 + 2"
[2]
Here is the behaviour through GHCI:
λ > b = SubIf (Expr (HInteger 2) Less (HInteger 1)) [(Expr (HInteger 45) Add (HInteger 45)), (Expr (HInteger 6) Add (HInteger 6))]
λ > c = SubIf (Expr (HInteger 2) Less (HInteger 3)) [(Expr (HInteger 5) Add (HInteger 5)), (Expr (HInteger 6) Add (HInteger 6))]
λ > a = If (Expr (HInteger 3) Less (HInteger 2)) [(Expr (HInteger 1) Add (HInteger 100)), (Expr (HInteger 2) Add (HInteger 2))] [b, c]
λ > eval b -- All False branches return a value of 1
1
λ > eval c
[10 12]
λ > eval a
[[10 12]]
This is my expected result. In the case of n number of sub if expressions, I will pick one list of the overall list as my branch to take before I go back to evaluate the loop guard and begin the next iteration of the program.
My data type:
data HVal
= HInteger Integer
| HBool Bool
| HString String
| HList [HVal]
| Expr HVal Op HVal
| EqExpr HVal Op HVal
| Neg HVal
| Assign HVal HVal
| Do HVal [HVal]
| If HVal [HVal] [HVal]
| SubIf HVal [HVal]
| Load String
deriving (Eq, Read)
My Parsers:
parseIf :: Parser HVal
parseIf = do
_ <- string "if"
spaces
_ <- string "("
cond <- (parseExpr <|> parseEqExpr <|> parseBool)
_ <- string ")->"
expr <- spaces *> many (parseExpression <* spaces)
expr' <- spaces *> many (parseExpression <* spaces)
return $ If cond expr expr'
parseSubIf :: Parser HVal
parseSubIf = do
_ <- string "[]"
spaces
_ <- string "("
cond <- (parseExpr <|> parseEqExpr <|> parseBool)
_ <- string ")->"
expr <- spaces *> many (parseExpression <* spaces)
return $ SubIf cond expr
My Evaluator:
eval :: HVal -> HVal
---------- EVALUATING PRIMITIVES ----------
eval val#(HString _) = val
eval val#(HInteger _) = val
eval val#(HBool _) = val
eval val#(HList _) = val
eval (Expr x op y) = evalExpr x op y
eval (If cond expr expr') = evalIf cond expr expr'
eval (SubIf cond expr) = evalSubIf cond expr
evalIf :: HVal -> [HVal] -> [HVal] -> HVal
evalIf cond expr expr' = if ((eval cond) == (HBool True))
then HList $ map eval expr
else HList $ (filter (/= (HInteger 1)) (map eval expr'))
evalSubIf :: HVal -> [HVal] -> HVal
evalSubIf cond expr = if ((eval cond) == (HBool True))
then HList $ map eval expr
else (HInteger 1)
I think that the error may be with my parser for the if-block. My thinking behind it was that the if block contains the conditional for the first branch and what it evaluates to and then a list of sub expressions wherein each element of the list contains the branch conditional and what it evaluates to.
This code runs fine:
(require syntax/parse/define (only-in racket [#%app racket:#%app]))
(define-syntax-parser #%app
[(_ Cond {~datum ?} Form1 ...)
#'(when Cond Form1 ...)]
[(_ Cond {~datum ??} Form1 ... {~datum :} Form2 ...)
#'(if Cond (begin Form1 ...) (begin Form2 ...))]
[(_ Xs ...)
#'(racket:#%app Xs ...)]
)
(#t ? (displayln 1))
(#t ?? (displayln 1) : (displayln 2))
However, I wish to change ?? to a single ?. Racket shows error, why doesn't Racket match the second syntax?
:: undefined;
cannot reference an identifier before its definition
Is Racket confused the if syntax with the right above when syntax? How to fix it to use the same ? for both when and if?
I found it out how, the when is defined first before the if in define-syntax-parser, and its syntax include ellipsis ... which matches everything following it, including the : in if-else.
Fixed it as below, put syntax for if first:
(require syntax/parse/define (only-in racket [#%app racket:#%app]))
(define-syntax-parser #%app
[(_ Cond {~datum ?} Form1 ... {~datum :} Form2 ...)
#'(if Cond (begin Form1 ...) (begin Form2 ...))]
[(_ Cond {~datum ?} Form1 ...)
#'(when Cond Form1 ...)]
[(_ Xs ...)
#'(racket:#%app Xs ...)]
)
(#t ? (displayln 1))
(#t ? (displayln 1) : (displayln 2))
I hava a language PLANG that supports evaluating a
polynomial on a sequence of points (numbers).
the language allows expressions of the
form {{ 𝒑𝒐𝒍𝒚 𝑪𝟏 𝑪𝟐 … 𝑪𝒌} {𝑷𝟏 𝑷𝟐 … 𝑷𝓵}} where all 𝐶𝑖 and all 𝑃𝑗 are
valid AE expressions (and both 𝑘 ≥ 1 and ℓ ≥ 1).
I was trying to write a parse for this language here is what I have so far:
(define-type PLANG
[Poly (Listof AE) (Listof AE)])
(define-type AE
[Num Number]
[Add AE AE]
[Sub AE AE]
[Mul AE AE]
[Div AE AE])
(: parse-sexpr : Sexpr -> AE)
;; to convert s-expressions into AEs
(define (parse-sexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(list '+ lhs rhs) (Add (parse-sexpr lhs)
(parse-sexpr rhs))]
[(list '- lhs rhs) (Sub (parse-sexpr lhs)
(parse-sexpr rhs))]
[(list '* lhs rhs) (Mul (parse-sexpr lhs)
(parse-sexpr rhs))]
[(list '/ lhs rhs) (Div (parse-sexpr lhs)
(parse-sexpr rhs))]
[else (error 'parse-sexpr "bad syntax in ~s"
sexpr)]))
(: parse : String -> PLANG)
;; parses a string containing a PLANG expression to a PLANG AST
(define (parse str)
(let ([code (string->sexpr str)])
(parse-sexpr (code) )))
(test (parse "{{poly 1 2 3} {1 2 3}}")
=> (Poly (list (Num 1) (Num 2) (Num 3))
(list (Num 1) (Num 2) (Num 3))))
(test (parse "{{poly } {1 2} }")
=error> "parse: at least one coefficient is
required in ((poly) (1 2))")
(test (parse "{{poly 1 2} {} }")
=error> "parse: at least one point is
required in ((poly 1 2) ())")
when I'm trying to make it run I get the errors:
Type Checker: Cannot apply expression of type (U (Listof Sexpr) Boolean Real String Symbol), since it is not a function type in: (code)
. Type Checker: type mismatch
expected: Poly
given: AE in: (parse-sexpr (code))
. Type Checker: Summary: 2 errors encountered in:
(code)
(parse-sexpr (code))
>
Any help would be appreciated..
The first problem is caused by an extra pair of parentheses. Keep in mind that in Racket, Typed Racket, and #lang pl, parentheses usually mean function application like this:
(function argument ...)
So when you write (code), it tries to interpret code as a function, to call it with zero arguments.
You can fix this problem by replacing (code) with code in the body of the parse function.
(define (parse str)
(let ([code (string->sexpr str)])
(parse-sexpr code)))
The second problem happens because you specified that the parse function should return a PLANG, but it instead returns the result of parse-sexpr which returns an AE.
Another way of wording this is that you've implemented parsing for AEs, but not for PLANGs.
I need to write a parser in racket for this abstract syntax:
;; <DE> ::= <num>
;; | {distribution <num>*}
;; | {uniform <num> <num>}
;; | {+ <DE> <DE>}
;; | {- <DE> <DE>}
;; | {* <DE> <DE>}
;; | {with {<id> <DE>} <DE>}
;; | <id>
(define-type Binding
[binding (name symbol?) (named-expr DE?)])
(define-type DE
[distribution (values (listof number?))]
[id (name symbol?)]
[binop (op procedure?) (lhs DE?) (rhs DE?)]
[with (b Binding?) (body DE?)])
What I have so far is:
(define (parse sexp)
(match sexp
[(? symbol?) (id sexp)]
[sexp (distribution (values (list sexp)))]
[(list '+ l r) (binop + (parse l) (parse r))]
[(list '- l r) (binop - (parse l) (parse r))]
[(list '* l r) (binop * (parse l) (parse r))]))
Note that {uniform a b}, is a discrete uniform distribution from a to b (inclusive). If a > b, then it's empty.
This is not working as expected and I can't get it right. There aren't resources on the web to help me, or at least I couldn't find them.
Is anyone able to explain me where I'm wrong and what the solution could be? I really have no clue. Thanks!
I am trying to write a simple parser which creates a sxml-expression from a string, e. g.
"This is a [Test]" ===> (item "This is a" (subitem "Test"))
Anybody who is wondering about the square brackets within the given example may have a look at the so called Leiden conventions.
This is the code I have written so far:
(define my-sequence '("this" "[" "is" "a" "]" "test"))
(define (left-square-bracket? item)
(or (equal? item "[")
(eq? item #\x005b)))
(define (right-square-bracket? item)
(or (equal? item "]")
(eq? item #\x005d)))
(define (parse-sequence sequence)
(cond ((null? sequence) '())
((left-square-bracket? (car sequence))
(let ((subsequence (get-subsequence (cdr sequence))))
(list subsequence)))
(else
(cons (car sequence)
(parse-sequence (cdr sequence))))))
(define (get-subsequence sequence)
(if (right-square-bracket? (car sequence))
'()
(cons (car sequence)
(get-subsequence (cdr sequence)))))
Evaluating (parse-sequence my-sequence) yields ("this" ("is" "a")). A nested expression has been created, but the program finished without having evaluated the last item "test". The question is, how do I return from get-subsequence to parse-sequence?
Any help is appreciated, many thanks in advance! :)
To address your initial questions, how to return multiple values: use the "values" form. Here is an example implementation where the inner procedure returns both the remaining list to be processed and the result so far. It recurses on opening brackets.
(define (parse-sequence lst)
(define (parse-seq lst)
(let loop ((lst lst) (res null))
(cond
((null? lst) (values null res))
((string=? (car lst) "[")
(let-values ([(lst2 res2) (parse-seq (cdr lst))])
(loop lst2 (append res (list res2)))))
((string=? (car lst) "]")
(values (cdr lst) res))
(else
(loop (cdr lst) (append res (list (car lst))))))))
(let-values ([(lst res) (parse-seq lst)])
res))
then
(parse-sequence '("this" "is" "a" "test"))
(parse-sequence '("this" "[" "is" "a" "]" "test"))
(parse-sequence '("this" "[" "is" "[" "a" "]" "]" "test"))
will yield
'("this" "is" "a" "test")
'("this" ("is" "a") "test")
'("this" ("is" ("a")) "test")
I made some progress by using open-input-string in combination with read-char:
(define my-sequence (open-input-string "this [is a] test"))
(define (parse-sequence sequence)
`(item
,#(let loop ((next-char (read-char sequence)))
(cond ((eof-object? next-char) '())
((left-square-bracket? next-char)
(let ((subsequence (get-subsequence sequence)))
(cons subsequence
(loop (read-char sequence)))))
(else
(cons next-char
(loop (read-char sequence))))))))
(define (get-subsequence sequence)
`(subitem
,#(let loop ((next-char (read-char sequence)))
(if (right-square-bracket? next-char)
'()
(cons next-char
(loop (read-char sequence)))))))
(parse-sequence my-sequence)
===> (item #\t #\h #\i #\s #\space (subitem #\i #\s #\space #\a) #\space #\t #\e #\s #\t)
Now work goes on, step by step. :)
Any comments and suggestions are still appreciated. :)