Let's say I have the following code:
(let ([a 3]
[b 4])
(+ a b))
To match this expression I try:
(match exp
(`(let ([,id ,val] ...) body) <code for handling this>)
I was hoping id will match to a and val will match to 3
But id matches to (a b), and val matches to (3 4) instead.
Is there any way I can achieve the first scenario ?
From the syntax - it looks like you want to use an Indiana style pattern matcher.
There is a port to Racket here. Save "imatch.rkt" in the same folder as your file and then use (require "imatch.rkt").
https://github.com/soegaard/indiana
Documentation: http://www.cs.indiana.edu/chezscheme/match/
The alternative is to use the old-style pattern syntax in Racket.
Use (require mzlib/match) to get the old syntax.
The documentation is here: http://docs.racket-lang.org/mzlib/mzlib_match.html
Related
As a part of a Tic Tac Toe playing bot, I need a function that evaluates combinations of tiles to points. The code would look something like this:
(case combination
("EEEEE" 0)
("EEEEP" 1)
("EEEPE" 1)
("EEEPP" 2)
("EEPEE" 1)
("EEPEP" 2)
("EEPPE" 2)
("EEPPP" 3)
("EPEEE" 1)
("EPEEP" 2)
("EPEPE" 2)
("EPEPP" 3)
("EPPEE" 2)
("EPPEP" 3)
("EPPPE" 3)
("EPPPP" 4)
("PEEEE" 1)
("PEEEP" 2)
("PEEPE" 2)
("PEEPP" 3)
("PEPEE" 2)
("PEPEP" 3)
("PEPPE" 3)
("PEPPP" 4)
("PPEEE" 2)
("PPEEP" 3)
("PPEPE" 3)
("PPEPP" 4)
("PPPEE" 3)
("PPPEP" 4)
("PPPPE" 4)
("PPPPP" 5))
(This is not the place to discuss the value of such an approach, for it is used for reasons unrelated to the question)
The problem is that case uses a predicate that doesn't return true for identical strings that aren't the same object (hard to find if it's eq or eql). How can you change that?
EDIT: I solved the original problem by converting the string into a corresponding binary number, which can be compared using eql or used as an index in a list.
Use alexandria:switch from the alexandria library, available from quicklisp.
(switch (combination :test #'string=)
("FOO" …)
…)
Your code just calculates (count #\P combination).
Usually I would convert the string in a number and compute with it. Using LOGCOUNT to get the on bits or something. Even if I were using a large CASE-like switch, I would convert the string once to a number, instead of doing a multitude of string comparisons.
You could write a macro:
(defmacro string-case (key &rest forms)
(let ((k (gensym "KEY")))
`(let ((,k ,key))
(cond
,#(loop for (str . body) in forms
collect `((string= ,k ,str) ,#body))))))
And then use it like case. Note that this macro will check each substring one at a time (up to 32 branches in your case), which is less efficient than eg looking at the first character and deciding what to do, then looking at the next character and so on (5-10 branches in your case), which is less efficient than doing what you actually intend (eg counting #\P) (this can be done with 5-6 easily predicted branches, or maybe 10 depending on implementation). Of these options, the second generated the most code, then the first, then the third.
Another approach would be to convert combination to a symbol. The resulting code will look like this:
(case (intern combination)
(EEEEE 0)
(EEEEP 1)
(EEEPE 1)
...)
But you need to keep in mind that intern operates at runtime in the context of current package (*package*), which means that if this is part of a function that is called outside of the package where it's defined, it will not work. There are 2 ways to work around this (basically, two variations of one): either intern in the package ((intern combination <your-package>)) or intern as keyword. In the later case, the whole form will look like this:
(case (intern combination :keyword)
(:EEEEE 0)
(:EEEEP 1)
(:EEEPE 1)
...)
Also worth noting may be performance considerations. They shouldn't be a problem as, although interning is a rather heavy operation, initially, when it's called repeatedly on an already interned symbol it's, basically, just a dictionary lookup.
Another solution may be to define the rules as a list, and search through the list for the matching string.
(defun match-combination (combination)
(let ((rules '(("EEEEE" 0)
("EEEEP" 1)
("EEEPE" 1)
...)))
(cadr (find combination rules :key #'car :test #'string=))))
Why doesn't this work?
( ((lambda () (lambda (x) (funcall #'1+ x)))) 2)
; yields Compile-time error: illegal function call
I ran into a situation like this and it later turned out that a funcall fixes it, i.e.
(funcall ((lambda () (lambda (x) (funcall #'1+ x)))) 2) ; => 3
I'm confused because it seems like the first one should work, because I actually have a function I'm calling, not just a symbol that may belong to either namespace (i.e. (type-of ((lambda () #'1+))) ; => FUNCTION). I thought it would be kind of like how you don't need to funcall a lambda for example, e.g.((lambda (x) x) :HI) ; => :HI. What am I missing?
Common Lisp uses the word form for everything which can be evaluated.
A form is either
a symbol like foo
a compound form, a list, see below
or a self-evaluating object (like numbers, characters, arrays, strings, ...).
A compound form is either
a special form (<special-operator> ...)
a lambda form like (lambda (...) ...)
a macro form (<macroname> ...)
or a function form (<functionname> ...).
Above is the set of compound forms. The ANSI Common Lisp specification provides no way to add a new type of forms or a different syntax. The interface of what forms the functions like EVAL or COMPILE accept is not extensible.
So something like
(((lambda (foo)
(lambda (bar)
(list foo bar)))
1)
2)
is not valid Common Lisp. This is not meaningful in Common Lisp:
( <not a lambda form,
not a special operator,
not a macro name
and not a function name>
2)
Note that Common Lisp allows lambda forms, special operators, macro names and function names as the first element in a compound form. But it does not allow variables and it does not allow other compound forms as the first element in a compound form.
Means this is not meaningful in Common Lisp:
( <a function form> 2)
Thus ((foo 1) 2) or (((foo 1) 2) 3) or ((((foo 1) 2) 3) 4) or (((((foo 1) 2) 3) 4) 5) is not legal in Common Lisp. You get the idea. To call function objects returned from function calls, we have to use (funcall (foo ...) ...). This makes calling returned function objects more obvious than just ((foo ...) ...).
Let's praise the designers of Common Lisp for this feature. Otherwise I might have to look at possibly meaningful code beginning with
(((((((((((( .....
and it would be very hard to figure out what it does. Basically that would be write-only code.
Your question:
Why must I funcall a function returned from another?
The short answer: because the syntax does not allow other ways, in Common Lisp.
The syntax of Common Lisp requires that, everytime you want to call a function through a compund form of the type:
(f a1 a2 ... an)
the first element of the list, f, must be a symbol denoting a function name, or a list denoting a lambda expression, i.e. (see the manual):
lambda expression n. a list which can be used in place of a function name in certain contexts to denote a function by directly describing its behavior rather than indirectly by referring to the name of an established function; its name derives from the fact that its first element is the symbol lambda.
So, this basically means that you cannot have as first element any expression that returns a function as value. In those cases, you must use funcall.
So, in your second example, the first argument of the funcall is ((lambda () (lambda (x) (funcall #'1+ x)))), which is a correct coumpound form, in which the first element of the list is the lambda expression (lambda () (lambda (x) (funcall #'1+ x))) (applied to an empty list of arguments).
In the first example, instead, you have as first element of the list an expression returning a function, so that you must use funcall.
I have read this article and then modified my code below:
(defparameter *my-fun* 1)
(defun my-func (v0)
(setf (symbol-function '*my-fun*)
(lambda (v1)
(+ v0 v1)))
'*my-fun*)
And call it in this way ((my-func 2) 3),but it also report "illegal function call". I think my code is keeping with lambda calculus,but where is wrong.
In my opinion, (my-func 2) returns symbol *my_fun*, and the function cell of *my-fun* points to a function object, so ((my-func 2) 3) => (*my-fun* 3) => ((lambda (v1) (+ 2 v1)) 3) => (+ 2 3) => 5
This works: First your identical definitions:
(defparameter *my-fun* 1)
(defun my-func (v0)
(setf (symbol-function '*my-fun*)
(lambda (v1)
(+ v0 v1)))
'*my-fun*)
However, invoke using funcall:
(funcall (my-func 2) 3)
In scheme - how can I evaluate a simple expression (containing only + * - / () and 0-9 digits) given as a string?
I've tried to first turn the expression into a postfix expression but I guess I'm doing something wrong.
Thank you
Maybe you can use this parser for infix expressions.
http://planet.racket-lang.org/package-source/soegaard/infix.plt/1/0/planet-docs/manual/index.html
Here is a small example (it takes a while for the library to install - it seems the old Schematics test suite takes forever to install these days - I need to switch to a builtin one).
#lang at-exp racket
(require (planet soegaard/infix)
(planet soegaard/infix/parser))
(display (format "1+2*3 is ~a\n" #${1+2*3} ))
(parse-expression #'here (open-input-string "1+2*3"))
The output will be:
1+2*3 is 7
.#<syntax:6:21 (#%infix (+ 1 (* 2 3)))>
The function parse-expression parses the expression in the string and
returns a syntax-object that resembles the output of ToExpression.
I just discovered Racket a few days ago, and I'm trying to get more comfortable with it by writing a little script that generates images to represent source code using #lang slideshow.
I know that when programming in a functional paradigm it's good practice to create almost all your variables with let, but I find that it introduces too many levels of nesting and that Racket's let has an overcomplicated API which requires superfluous parentheses. I'm sure this is to remove ambiguity when using let in more powerful ways, but for my purposes it's just an annoyance. Consequently, I'm creating all my variables with define, and writing blocks with begin if I need to (such as in the body of an if statement).
The problem is that I've repeatedly been getting what seem to be very mysterious errors. I'm sure I'm just making some silly beginner's mistake, being new to the language, but I really can't seem to find the source of the complaint.
Here's the offending code:
(define sub-code (foldr ht-append (rectangle 0 0) (map internal-style (rest code))))
although what we're defining sub-code to seems pretty irrelevant. If I replace it with
(define sub-code '())
I receive the same error. DrRacket is saying that define is being used in an expression context. I understand what this error would normally mean - IE that it would raise when you write code like (print (define x 10)), but I can't see what would trigger it here.
If it helps, this define is at the beginning of a begin block, inside an if statement
(if (list? code)
(begin
(define sub-code '())
; a few more define statements and finally an expression ))
The specific error message DrRacket is printing is
define: not allowed in an expression context in: (define sub-code (quote ()))
I thought maybe define isn't allowed in begin blocks, but I checked the docs and one of the examples for begin is
(begin
(define x 10)
x)
So I don't really know what to do. Thanks in advance!
Definitions are allowed in a 'body' context, like in lambda and let among others. The consequent and alternate clauses of if are not body contexts; they are expression contexts and therefore definitions are not allowed.
begin is special - begin in a body context allows definitions, but begin in an expression contexts forbids definitions. Your case falls in to the later.
For example:
(define (foo . args) #| body context #|)
(define foo (lambda args #| body context |#))
(define (foo . args)
(let (...)
#| body context |#))
Syntactic keywords that requires expressions: if, cond, case, and, or, when, unless, do, begin. Check out the formal syntax in any Scheme report (r{4,5,6,7}rs); look for <body>, <sequence>, <command>, and <expression>.
Also, if you need a body context in an expression, just wrap a let syntactic form, as such:
(if test
(let ()
(define foo 'foo)
(list foo foo))
alternate)
As GoZoner explained, you can't use define in an expression context.
What could you do instead?
Use let:
(if (list? code)
(let ([x '()])
x)
...
Or it would work with an "empty" let and define:
(if (list? code)
(let ()
(define x '())
x)
...
But that's a bit silly.
Or use cond and define:
(cond [(list? code)
(define x '())
x]
...
This last way -- using cond and define -- is closest to what the current Racket style guide recommends.
Here's more details, from the Racket docs.
The different contexts are required because macros must expand differently, depending on which language forms are allowed.
As others have said, definitions are not allowed in expression contexts ("expr ..." in the docs), but are ok in other contexts.
In other doc entries, "body ..." indicates an internal-definition context (guide, reference), for example in lambda bodies, and "form ..." indicates all non-expression contexts, like in the docs for begin.
Or you could wrap the expressions in (begin)
e.g.(begin
(define x 10)
(define y 100)
(define z 1000))
This is with SBCL 1.0.55 on Debian squeeze. I'm probably missing something obvious, but I'm a beginner, so please bear with me.
CL-USER> (defparameter x 0)
CL-USER> (case x (t 111) )
111
So it looks like case here is matching the variable x with the truth symbol t. This happens with everthing I've tried; this x is just an example. I don't see why this would happen. Since case uses eql for matching, I tried
CL-USER> (eql x t)
NIL
So, eql does not match x and t. What am I missing? Thanks in advance.
Described in the CASE documentation.
otherwise-clause::= ({otherwise | t} form*)
The syntax says that an otherwise clause is either (otherwise form-1 ... form-n) or (t form-1 ... form-n). Note that the syntax says {otherwise | t}. The vertical bar is an OR in a syntax specification. So the marker for an otherwise clause is either otherwise or t.
That means, if your case clause begins with otherwise or t, then we have an otherwise-clause.
In the case construct in Common Lisp, t, used by itself, is equivalent to default in C; that is, it's evaluated if the expression doesn't match any of the other cases. If you want to match the actual symbol t, use (t) instead.