[beginner] I need a macro (probably)

Discussion of Common Lisp
Post Reply
vega
Posts: 2
Joined: Thu Sep 05, 2013 7:56 am

[beginner] I need a macro (probably)

Post by vega » Thu Sep 05, 2013 8:59 am

Hello,
I am trying to parse some text and I am using the esrap library. Even if you are not familiar with it, please read on because you can perhaps still answer my question.

Code: Select all

(require :esrap)

(defpackage :my-grammar
  (:use :cl :esrap))

(in-package :my-grammar)

(defparameter *currency-names*
  '((usd . "USD")
    (eur . "EUR")
    (gbp . "GBP")))

(defun name-for-symbol (symbol table)
  (cdr (assoc symbol table)))

(defun symbol-for-name (name table)
  (car (rassoc name table :test 'equal)))

(defrule currency (or "USD" "EUR" "GBP") ;;esrap's defrule is a macro
  (:lambda (name)
    (symbol-for-name (text name) *currency-names*)))
The above works as intended, that is it recognizes the input if it is one of the three currency names and returns the corresponding symbol.

Code: Select all

MY-GRAMMAR> (parse 'currency "USD")
USD
NIL
But I want to change the definition of the rule like this, so that the names of the currencies are not hard-coded, because this would avoid code duplication and because I have to parse other things in a way similar to currencies.

Code: Select all

(defrule currency (or (all-names *currencies*)) ;; this is not working
  (:lambda (name)
    (symbol-for-name (text name) *currency-names*)))
where I have tried all-names to be

Code: Select all

(defun all-names (table)
  (mapcar #'cdr table))
and

Code: Select all

(defmacro all-names (table)
  `(mapcar #'cdr ,table))
among other things

I guess all-names must be a macro and not a function and I guess the problem is that my all-names returns ("USD" "EUR" "GBP"), while the "or" in defrule expects the list to be spliced. So if only I could create the list (or "USD" "EUR" "GBP") and give it to defrule. Also I read somewhere that I should use some instead of or in similar(?) cases, but some requires a predicate (in addition to a list) and I can't think of one.

I assume this might be simple, but I am a beginner in lisp. Any help would be appreciated. For anyone wishing to try, you should be able to run the above code if you load esrap using quicklisp first.

Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

Re: [beginner] I need a macro (probably)

Post by Goheeca » Thu Sep 05, 2013 12:28 pm

You can write this macro:

Code: Select all

(defmacro all-names (table)
  `(or ,@(mapcar #'cdr table))
and use it this way:

Code: Select all

(defrule currency (all-names *currencies*)
  (:lambda (name)
    (symbol-for-name (text name) *currency-names*)))
According to the source code there is an option use a predicate so you can create one:

Code: Select all

(defun member-of-currencies (elem)
  (member elem (mapcar #'cdr *currencies*)))

(defrule currency (member-of-currencies)
  (:lambda (name)
    (symbol-for-name (text name) *currency-names*)))
I hard-coded the variable *currencies*, because I don't know how exactly is treated the predicate by the rule class and wether you can pass arguments to it.
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Post Reply