Polymorphic function `car' could not be applied to arguments - racket

I want to use typed/racket to implement the "LET" language in eopl, but I encounter problems:
I try to implement three functions( empty-env, extend-env, apply-env ), but I don't know how to label the type information, and racket cannot automatically deduce the types of these three functions.
I tried to use any, but I still encountered problems:
(: empty-env (-> Any))
(define empty-env
(lambda () (list 'empty-env)))
(: extend-env (-> Any Any Any Any))
(define extend-env
(lambda (var val env)
(list 'extend-env var val env)))
(: apply-env (-> Any Any Any))
(define apply-env
(lambda (env search-var)
(cond [(eqv? (car env) 'empty-env) (None)]
[(eqv? (car env) 'extend-env)
(let ([saved-var (cadr env)]
[saved-val (caddr env)]
[saved-env (cadddr env)])
(if (eqv? search-var saved-var)
saved-val
(apply-env saved-env search-var)))]
[else (None)])))
The error prompted by racket is:
Type Checker: Polymorphic function `car' could not be applied to arguments:
Domains: (Listof a)
(Pairof a b)
Arguments: Any
in: (car env)
How can I correctly label the type information

#lang typed/racket
(define-type EmptyEnv '(empty-env))
(define-type Env (U EmptyEnv
(List 'extend-env Any Any Env)))
(define (None) 'None)
(: empty-env (-> Env))
(define empty-env
(lambda () (list 'empty-env)))
(: extend-env (-> Any Any Env Env))
(define extend-env
(lambda (var val env)
(list 'extend-env var val env)))
(: apply-env (-> Env Any Any))
(define apply-env
(lambda (env search-var)
(cond [(eqv? (car env) 'empty-env) (None)]
[(eqv? (car env) 'extend-env)
(let ([saved-var (cadr env)]
[saved-val (caddr env)]
[saved-env (cadddr env)])
(if (eqv? search-var saved-var)
saved-val
(apply-env saved-env search-var)))]
[else (None)])))
(define env (extend-env 'a 42 (empty-env)))
env
(apply-env env 'a)

I've found that having a list of arbitrary length of mixed types doesn't really play well with typed Racket (True, but not relevant to OP's original code; I was looking at an earlier version of mine when I said that), and that Any should be used sparingly (If you're using it for all types, might as well use normal Racket, for one). Using a list of pairs for your environment (Or better yet a list of structs, but I'm not familiar with EOPL and what it covers) is the way to go here. Something like:
#lang typed/racket
;; Type that associates a symbol with an arbitrary value
(define-type Binding (Pair Symbol Any))
;; A list of these is your environment/symbol table.
(define-type Env (Listof Binding))
(: empty-env (-> Env))
(define empty-env
(lambda () '()))
(: extend-env (-> Symbol Any Env Env))
(define extend-env
(lambda (var val env)
(cons (cons var val) env)))
;; made up so the below will compile
(define None (lambda () 'None))
(: apply-env (-> Env Symbol Any))
(define apply-env
(lambda (env search-var)
(if (null? env)
(None)
(let ([saved-var (caar env)]
[saved-val (cdar env)])
(if (eqv? search-var saved-var)
saved-val
(apply-env (cdr env) search-var))))))

Related

How to write LISP macro with double quasi quotation in scheme

I need to write the lisp macro in scheme (please on hygienic macros and syntax-rules etc) that will have function call and Alist as argument
I want function and macro that call that function to have syntax like this:
(foo '(10 (a (lambda () (display "10")) b (lambda () (display "20"))))
or macro without quotes.
My last code is working, but not sure if this is how you suppose to write function/macro like this. It seems that I need double backquote but don't know how to write it. (I'm right now reading On Lips by Paul Graham and he said that double backquote is very hard and only need by macros defining macros, but It seems that this is what I need).
(define (foo expr)
`(list ,(car expr)
(,(string->symbol "quasiquote") ,(pair-map (lambda (a b)
(cons (symbol->string a)
(list 'unquote b)))
(cadr expr)))))
(define-macro (bar expr)
(foo expr))
(define xx (bar (10 (a 20 b (lambda () (display "x") (newline))))))
;; (list 10 `((a . ,20) (b . ,(lambda () (display "x") (newline))))
(define bfn (cdr (assoc "b" (cadr xx)))))
(bfn)
;; "x"
and here is definition of pair-map
(define (pair-map fn seq-list)
"(seq-map fn list)
Function call fn argument for pairs in a list and return combined list with
values returned from function fn. It work like the map but take two items from list"
(let iter ((seq-list seq-list) (result '()))
(if (null? seq-list)
result
(if (and (pair? seq-list) (pair? (cdr seq-list)))
(let* ((first (car seq-list))
(second (cadr seq-list))
(value (fn first second)))
(if (null? value)
(iter (cddr seq-list) result)
(iter (cddr seq-list) (cons value result))))))))
with (string->symbol "quasiquote") I was able not to use double backquote, can this be written with double backquote/quasiquote? How this should look like?
I'm asking if this can be written different way so I can fix few issues in my own lisp interpreter (not sure if is working correctly but it seems that this final version works the same in guile).
I came up with shorter quasiquote version, but still it require inserting symbols:
(define (foo expr)
`(list ,(car expr)
(,'quasiquote ,(pair-map (lambda (a b)
`(,(symbol->string a) . (,'unquote ,b)))
(cadr expr)))))

How to define function in LISP that recursively return back quoted list

I have problem with macros in my lisp interpreter writtein in JavaScript. the problem is in this code:
(define log (. console "log"))
(define (alist->object alist)
"(alist->object alist)
Function convert alist pairs to JavaScript object."
(if (pair? alist)
((. alist "toObject"))))
(define (klist->alist klist)
"(klist->alist klist)
Function convert klist in form (:foo 10 :bar 20) into alist
in form ((foo . 10) (bar . 20))."
(let iter ((klist klist) (result '()))
(if (null? klist)
result
(if (and (pair? klist) (pair? (cdr klist)) (key? (car klist)))
(begin
(log ":::" (cadr klist))
(log "data" (. (cadr klist) "data"))
(iter (cddr klist) (cons (cons (key->string (car klist)) (cadr klist)) result)))))))
(define (make-empty-object)
(alist->object '()))
(define empty-object (make-empty-object))
(define klist->object (pipe klist->alist alist->object))
;; main function that give problems
(define (make-tags expr)
(log "make-tags" expr)
`(h ,(key->string (car expr))
,(klist->object (cadr expr))
,(if (not (null? (cddr expr)))
(if (and (pair? (caddr expr)) (let ((s (caaddr expr))) (and (symbol? s) (eq? s 'list))))
`(list->array (list ,#(map make-tags (cdaddr expr))))
(caddr expr)))))
(define-macro (with-tags expr)
(make-tags expr))
I call this macro using this code:
(define (view state actions)
(with-tags (:div ()
(list (:h1 () (value (cdr (assoc 'count (. state "counter")))))
(:button (:onclick (lambda () (--> actions (down 1)))) "-")
(:button (:onclick (lambda () (--> actions (up 1)))) "+")))))
which should expand to almost the same code:
(define (view state actions)
(h "div" (make-empty-object)
(list->array (list
(h "h1" (make-empty-object) (value (cdr (assoc 'count (. state "counter")))))
(h "button" (klist->object `(:onclick ,(lambda () (--> actions (down 1))))) "-")
(h "button" (klist->object `(:onclick ,(lambda () (--> actions (up 1))))) "+")))))
This function works. I have problem with expanded code using my macro that call the main function, don't know how LIPS should behave when it find:
(:onclick (lambda () (--> actions (down 1))))
inside code and you try to process it like this:
,(klist->object (cadr expr))
Right now my lisp works that lambda is marked as data (have data flag set to true this is a hack to prevent of recursive evaluation of some code from macros) and klist->object function get lambda code as list, instead of function.
How this should work in Scheme or Common Lisp? Should klist->object get function object (lambda get evaluated) or list structure with lambda as first symbol? If second then how I sould write my function and macro to evaluate lambda should I use eval (kind of hack to me).
Sorry don't know how to test this, with more bug free LISP.
EDIT:
I've tried to apply the hint from #jkiiski in guile (because in my lisp it was not working)
;; -*- sheme -*-
(define nil '())
(define (key? symbol)
"(key? symbol)
Function check if symbol is key symbol, have colon as first character."
(and (symbol? symbol) (eq? ":" (substring (symbol->string symbol) 0 1))))
(define (key->string symbol)
"(key->string symbol)
If symbol is key it convert that to string - remove colon."
(if (key? symbol)
(substring (symbol->string symbol) 1)))
(define (pair-map fn seq-list)
"(seq-map fn list)
Function call fn argument for pairs in a list and return combined list with
values returned from function fn. It work like the map but take two items from list"
(let iter ((seq-list seq-list) (result '()))
(if (null? seq-list)
result
(if (and (pair? seq-list) (pair? (cdr seq-list)))
(let* ((first (car seq-list))
(second (cadr seq-list))
(value (fn first second)))
(if (null? value)
(iter (cddr seq-list) result)
(iter (cddr seq-list) (cons value result))))))))
(define (klist->alist klist)
"(klist->alist klist)
Function convert klist in form (:foo 10 :bar 20) into alist
in form ((foo . 10) (bar . 20))."
(pair-map (lambda (first second)
(if (key? first)
(cons (key->string first) second))) klist))
(define (h props . rest)
(display props)
(display rest)
(cons (cons 'props props) (cons (cons 'rest rest) nil)))
(define (make-tags expr)
`(h ,(key->string (car expr))
(klist->alist (list ,#(cadr expr)))
,(if (not (null? (cddr expr)))
(if (and (pair? (caddr expr)) (let ((s (caaddr expr))) (and (symbol? s) (eq? s 'list))))
`(list->array (list ,#(map make-tags (cdaddr expr))))
(caddr expr)))))
(define-macro (with-tags expr)
(make-tags expr))
(define state '((count . 10)))
(define xxx (with-tags (:div ()
(list (:h1 () (cdr (assoc 'count state)))
(:button (:onclick (lambda () (display "down"))) "-")
(:button (:onclick (lambda () (display "up"))) "+")))))
but got error:
ERROR: Unbound variable: :onclick
I've found solution for my lisp, Here is code:
(define (pair-map fn seq-list)
"(seq-map fn list)
Function call fn argument for pairs in a list and return combined list with
values returned from function fn. It work like the map but take two items from list"
(let iter ((seq-list seq-list) (result '()))
(if (null? seq-list)
result
(if (and (pair? seq-list) (pair? (cdr seq-list)))
(let* ((first (car seq-list))
(second (cadr seq-list))
(value (fn first second)))
(if (null? value)
(iter (cddr seq-list) result)
(iter (cddr seq-list) (cons value result))))))))
(define (make-tags expr)
(log "make-tags" expr)
`(h ,(key->string (car expr))
(alist->object (quasiquote
;; create alist with unquote for values and keys as strings
,#(pair-map (lambda (car cdr)
(cons (cons (key->string car) (list 'unquote cdr))))
(cadr expr))))
,(if (not (null? (cddr expr)))
(if (and (pair? (caddr expr)) (let ((s (caaddr expr))) (and (symbol? s) (eq? s 'list))))
`(list->array (list ,#(map make-tags (cdaddr expr))))
(caddr expr)))))
So in my code I'm writing some kind of meta macro I'm writing quasiquote as list that will get evaluated the same as if I use in my original code:
(klist->object `(:onclick ,(lambda () (--> actions (down 1)))))
I'm using alist->object and new function pair-map, so I can unquote the value and convert key symbol to string.
is this how it should be implemented in scheme? not sure If I need to fix my lisp or macros are working correctly there.

little schemer drracket error cannot reference an identifier before its definition

beginner question,
just started the little schemer book and installed DrRacket on my macbook to try some of the code examples.
If I choose Racket language, the following code
#lang Racket
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
(atom? '())
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (lat? (cdr l)) )
(else #f))))
(lat? (a b))
will trigger error message:
a: unbound identifier in module in: a
if I choose R5RS language,
#lang R5RS
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
(atom? '())
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (lat? (cdr l)) )
(else #f))))
(lat? (a b))
I got an error message:
#%plain-module-begin: illegal use (not a module body) in: (#%plain-module-begin (module configure-runtime racket/base (require r5rs/init)) (define (atom? x) (and (not (pair? x)) (not (null? x)))) (atom? (quote ())) (define lat? (lambda (l) (cond ((null? l) #t) ((atom? (car l)) (lat? (cdr l))) (else #f)))) (lat? (a b)))
Anyone know what I did wrong?
Thanks
Looks like that last call should be
(lat? '(a b))
... no?
(Also: I would recommend using #lang racket in general, but I strongly suspect that your problem R5RS arises because you're "setting the language twice"; if you start your program with #lang R5RS, you don't need to change the language level. Conversely, if you set the language level, you shouldn't start your program with #lang R5RS. If you do both, I'm guessing you get the error message you saw.)

Scheme macro expansion shows variable is unbound

I am writing a simple lisp interpreter as I read Lisp in Small Pieces, but I am stuck on this error for over 2 hours now. I am defining a local genv variable but still I get this error. There must be some macro expansion thing I can't understand, I have checked the expansion using a quote, and it seems to be OK. Please if someone can shed some light it would be great. (The code works with r5rs language and guile scheme)
;; Macro to print it's given arguments line by line and end with a ------
(define-syntax println
(syntax-rules ()
((_ expr expr* ...) (begin (display expr)
(newline)
(println expr* ...)))
((_ expr) (begin (display expr) (newline)))
((_) (display "--------\n"))))
(define (evaluate expr env)
(begin (println "Evaluating" expr)
(if (not (pair? expr))
(cond ((symbol? expr) (lookup env expr))
((or (number? expr) (string? expr) (char? expr) (boolean? expr) (vector? expr)) expr)
(else (error "Cannot evaluate" expr)))
;; not atom
(case (car expr)
((quote) (cadr expr))
;; (define name expr)
((define) (update (cadr expr) (caddr expr) env))
((if) (if (evaluate (cadr expr) env)
(evaluate (caddr expr) env)
(evaluate (cadddr expr) env)))
((begin) (eprogn (cdr expr) env))
((set!) (update (cadr expr) (evaluate (caddr expr) env) env))
((lambda) (make-function (cadr expr) (cddr expr) env))
(else (invoke (evaluate (car expr) env)
(evlis (cdr expr) env)))))))
;; Evaluates all the expressions (exprs) in the given environment (env)
(define (eprogn exprs env)
(if (pair? exprs)
;; False when exprs contains just one item
(if (pair? (cdr exprs))
(begin (evaluate (car exprs) env)
(eprogn (cdr exprs) env))
(evaluate (car exprs) env))
'()))
(define (evlis exprs env)
(if (pair? exprs)
(cons (evaluate (car exprs) env)
(evlis (cdr exprs) env))
'()))
;; Makes a new applicable function, that closes the environment (env)
(define (make-function vars body env)
(lambda (vals)
(eprogn body (extend-environment env vars vals))))
(define (invoke fn args)
(if (procedure? fn)
(fn args)
(error "Not a function" fn)))
;; Environment suite
;; Helper macros for working with an environment vector
;; Returns the parent environment of (env)
(define-syntax parent-env-of
(syntax-rules ()
((parent-env-of env) (vector-ref env 0))))
;; Returns the bind-map of (env)
(define-syntax bind-map-of
(syntax-rules ()
((bind-map-of env) (vector-ref env 1))))
;; Sets the parent environment of (env)
(define-syntax set-parent-env!
(syntax-rules ()
((set-parent-env! env parent-env) (vector-set! env 0 parent-env))))
;; Sets the bind-map of (env)
(define-syntax set-bind-map!
(syntax-rules ()
((set-bind-map! env bind-map) (vector-set! env 1 bind-map))))
;; Makes a new environment with the parent env set to (parent-env)
(define (make-new-environment parent-env)
(let ((new-env (vector #f #f)))
(begin
(set-parent-env! new-env parent-env)
(set-bind-map! new-env '())
new-env)))
;; Searches for the value of (sym) in (env), raises
;; error if it can't find
(define (lookup env sym)
(if (null? env)
(error "Unbound name" sym)
(let ((val (assoc sym (bind-map-of env))))
(if (equal? val #f) (lookup (parent-env-of env) sym) (cdr val)))))
;; Create the binding update the (sym)'s value to (value) in the given (env)
(define (update sym value env)
(begin (println "Called update with env: " env "sym: " sym "value: " value)
(define new-bind-map (assoc-set! (bind-map-of env) sym value))
(set-bind-map! env new-bind-map)))
;; Extends an (env) by creating a new environment and setting the
;; bindings specified by the list of symbols (vars) and the
;; list of values (vals)
(define (extend-environment vars vals env)
(define new-env (make-new-environment env))
(update-all vars vals env))
;; Helper function
(define (update-all vars vals env)
(cond ((pair? vars) (if (not (pair? vals))
(error "More symbols than values to bind with")
(begin (update (car vars) (car vals) env)
(extend (cdr vars) (cdr vals) env))))
((null? vars) (if (not (null? vals))
(error "More values than symbols to bind with")
env))))
;; Helper macros for initializing the global env bind map
Problematic code:
;; ------------PROBLEM IN THESE MACROS------------------
(define-syntax _def-initial
(syntax-rules ()
((_def-initial name)
(update 'name 'void genv))
((_def-initial name value)
(update 'name value genv))))
(define-syntax _def-primitive
(syntax-rules ()
((_def-primitive name value arity)
(_def-initial name (lambda (args)
(if (equal? arity (length args))
(apply value args)
(error "Incorrect arity" (list 'name value))))))))
(define-syntax _fill-global-env
(syntax-rules ()
((_fill-global-env)
(begin
(println "Filling the environment")
(_def-primitive + (lambda (x y) (+ x y)) 2)
(_def-primitive - (lambda (x y) (- x y)) 2)
(_def-primitive * (lambda (x y) (* x y)) 2)
(_def-primitive / (lambda (x y) (/ x y)) 2))
)))
;; Racket and Guile SAY genv IS UNBOUND
(define get-global-environment
;; name must be `genv' coz of the above macros
(let ( (genv #f) )
(lambda ()
(if (equal? genv #f) ;; If uninitialized
(begin (set! genv (make-new-environment '()))
(println "Before filling: "genv)
(_fill-global-env)
(println "After filling: " genv)
genv)
genv))))
;; ------------------- END OF PROBLEMATIC CODE(IT SEEMS) ---------------
Continue:
;; - Start the interpreter
(define (main args)
;; Define the global environment
(define genv (get-global-environment))
(println "Global environment: " genv)
(let loop ((expr (read (current-input-port))))
(if (eof-object? expr)
(println "Done")
(begin (println (evaluate expr genv))
(loop (read (current-input-port)))))))
(main "")
Here's the error I receive from Racket (in problematic code's get-global-environment's body, not in main's body):
. . genv: undefined;
cannot reference undefined identifier
Scheme macros are hygienic. The genv you defined in get-global-environment is not the same as the genv in your _def-initial (which uses whatever genv was there when _def-initial was defined, which in this case would be the top-level one, which as you pointed out does not exist).
In order to make your macro work, you must adapt _fill-global-env, _def-primitive, and _def-initial to all take a genv parameter, so that _def-initial uses that genv instead of the top-level one.

Mutable versions of cadr, caddr, etc

I'm wondering how to implement mutable versions of cadr, caddr, and the likes in Racket without defining each one separately? ie. not
(define (mcadr exp)
(mcar (mcdr exp)))
It seems that for mutable lists or pairs, Racket only supports mcar and mcdr but not the "expanded" versions. Do I need to know and be good at macros to be able to do this?
Here's a macro solution:
#lang racket/base
(require racket/mpair (for-syntax racket/base))
(define-syntax (define-combinations stx)
(syntax-case stx ()
[(_ n) (integer? (syntax-e #'n))
(let ([n (syntax-e #'n)])
(define options (list (cons "a" #'mcar) (cons "d" #'mcdr)))
(define (add-options r)
(apply append
(map (λ (opt)
(map (λ (l) (cons (string-append (car opt) (car l))
(list (cdr opt) (cdr l))))
r))
options)))
(define combinations
(cdddr
(let loop ([n n] [r '(("" . x))])
(if (zero? n) r (append r (loop (sub1 n) (add-options r)))))))
(define (make-name combo)
(let ([s (string->symbol (string-append "mc" (car combo) "r"))])
(datum->syntax stx s stx)))
(with-syntax ([(body ...) (map cdr combinations)]
[(name ...) (map make-name combinations)])
#'(begin (define (name x) body) ...)))]))
(define-combinations 4)
(mcaddr (mlist 1 2 3 4 5))
You could do:
(define mcaar (compose mcar mcar))
(define mcadr (compose mcar mcdr))
;; ...
(define mcddddr (compose mcdr mcdr mcdr mcdr))
But there is no real getting around the repetition. Even in the Racket source (look in racket/src/list.c), the repetition is there, albeit prettified a little with C macros.