[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

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.
vega
 
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
Goheeca
 
Posts: 220
Joined: Thu May 10, 2012 12:54 pm


Return to Common Lisp

Who is online

Users browsing this forum: David Mullen and 4 guests