[beginner] I need a macro (probably)

Discussion of Common Lisp

[beginner] I need a macro (probably)

Postby vega » Thu Sep 05, 2013 8:59 am

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")

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))

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.
Posts: 1
Joined: Thu Sep 05, 2013 7:56 am

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

Postby 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).
User avatar
Posts: 198
Joined: Thu May 10, 2012 12:54 pm

Return to Common Lisp

Who is online

Users browsing this forum: No registered users and 3 guests