Scheme - dynamic scope and infinte loop - scope

I read a book about scheme, and it has the next example:
(define map
(lambda (f s)
(if (null? s)
'()
(cons (f (car s))
(map f (cdr s)))))
(map (lambda (s)
(set! s '(1 2 3 4))
'hello)
'(a b c d))
It say that in dynamic scope, we will enter to infinite loop. But why? As I understood, After we apply the application, we arrive to map with
f = (lambda (s)
(set! s '(1 2 3 4))
'hello)
and s= '(a b c d). Now, for the first run, we will apply f on (car '(a b c d):
((lambda (s)
(set! s '(1 2 3 4))
'hello)
(car '(a b c d)))
And now, It change a to be (1 2 3 4). And so on.. Where is the loop here?

I think what the author means is that after f (car s) executes, the value of s will be '(1 2 3 4), so the value of (cdr s) will be '(2 3 4), so you'll call (map f '(2 3 4)) every time ad infinitum.
However I do not think this is an accurate depiction of dynamic scoping. Since s is a parameter to the lambda (and thus not a free variable), only that parameter should be affected by the set! and the s of the map function should be unaffected. So there should be no infinite loop - whether you're using dynamic scoping or not. And if I translate the code to elisp (which is dynamically scoped), the code does in fact not cause an infinite loop. So I'd say your book is wrong in saying there'd be an infinite loop using dynamic scoping.

Related

NLP with Racket

I am studying NLP with Racket and Dr. Racket.
I am working with this code:
#lang racket
(define english-1
'((Initial (1))
(Final (9))
(From 1 to 3 by NP)
(From 1 to 2 by DET)
(From 2 to 3 by N)
(From 3 to 4 by BV)
(From 4 to 5 by ADV)
(From 4 to 5 by |#|)
(From 5 to 6 by DET)
(From 5 to 7 by DET)
(From 5 to 8 by |#|)
(From 6 to 7 by ADJ)
(From 6 to 6 by MOD)
(From 7 to 9 by N)
(From 8 to 8 by MOD)
(From 8 to 9 by ADJ)
(From 9 to 4 by CNJ)
(From 9 to 1 by CNJ)))
(define (getf x y)
(if (eq? (car x) y)
(cadr x)
(getf (cdr x) y)))
(define (initial-nodes network)
(list-ref (assoc 'Initial network) 1))
(define (final-nodes network)
(list-ref (assoc 'Final network) 1))
(define (transitions network)
(filter (lambda (x) (eq? (car x) 'From)) network))
(define (trans-node transition)
(getf transition 'From))
(define(trans-newnode transition)
(getf transition 'to))
(define (trans-label transition)
(getf transition 'by))
(define abbreviations
'((NP kim sandy lee)
(DET a the her)
(N consumer man woman)
(BV is was)
(CNJ and or)
(ADJ happy stupid)
(MOD very)
(ADV often always sometimes)))
(define (recognize network tape)
;; returns t if sucessfully recognizes tape - nil otherwise
(call/cc (lambda (return)
(define (recognize-next node tape network)
(if (and (null? tape) (member node (final-nodes network)))
(return #t) ; success
(for ([transition (transitions network)])
;; try each transition of the network
(when (equal? node (trans-node transition)) ; if it starts at the right node
(for ([newtape (recognize-move (trans-label transition) tape)])
;; try each possible new value of tape
(recognize-next (trans-newnode transition) newtape network))))))
(for ([initialnode (initial-nodes network)])
(recognize-next initialnode tape network))
null))) ; failed to recognize
(define (recognize-move label tape)
(if (or (eq? label (car tape))
(member (car tape) (assoc label abbreviations)))
(list (cdr tape))
(if (eq? label '|#|)
(list tape)
null)))
(require racket/trace)
(trace recognize-move)
(recognize-move english-1 '(hahaha))
The code seems to be mostly fine. However, I keep getting a error messaging related to the recognize-move function:
member: not a proper list: #f
And I thought I was dealing with lists... How can I solve this?
The problem is with this form:
(member (car tape) (assoc label abbreviations))
If assoc does not find anything the result is #f. (member 'anything #f) will not work. In Common Lisp false is the same as an empty list so member on false will work, but not in Scheme. You can perhaps make sure it's a list like this:
(member (car tape) (or (assoc label abbreviations) '()))
This is code translated from Common Lisp. In CL, nil is false and is also the empty list, (). In Racket, #f is false and is not the same as (). assoc wants to return false if it does not find a match: because of the way CL puns on false and the empty list, this means that (member ... (assoc ...)) will always work. In Racket it won't: you need to check to see if assoc failed to find a match.

A Replace Function in Lisp That Duplicates Mathematica Functionality

What is the easiest way to accomplish the following in a Mathematica clone or in any version of Lisp(any language is probably okay actually even Haskell)? It doesn't appear any lisps have a similar replace function.
Replace[{
f[{x, "[", y, "]"}],
f#f[{x, "[", y, y2, "]"}]
}
, f[{x_, "[", y__, "]"}] :> x[y],
Infinity]
and a return value of {x[y], f[x[y, y2]]}
It replaces all instances of f[{x_, "[", y__, "]"}] in args where x_ represents a single variable and y__ represents one or more variables.
In lisp the function and replacement would probably be the equivalent(forgive me I am not the best with Lisp). I'm looking for a function of the form (replace list search replace).
(replace
'(
(f (x "[" y "]"))
(f (f '(x "[" y y2 "]")))
)
'(f (x_ "[" y__ "]"))
'(x y)
)
and get a return value of ((x y) (f (x y y2))).
Let's give it another try.
First, install quicklisp and use it to fetch, install and load optima and alexandria.
(ql:quickload :optima)
(ql:quickload :alexandria)
(use-package :alexandria)
The functions from alexandria referenced below are ensure-list and last-elt. If you don't have them installed, you can use the following definitions:
(defun ensure-list (list) (if (listp list) list (list list)))
(defun last-elt (list) (car (last list)))
We define rules as functions from one form to another.
Below, the function tries to destructure the input as (f (<X> "[" <ARGS> "]"), where <ARGS> is zero or more form. If destructuring fails, we return NIL (we expect non-matching filters to return NIL hereafter).
(defun match-ugly-funcall (form)
(optima:match form
((list 'f (cons x args))
(unless (and (string= "[" (first args))
(string= "]" (last-elt args)))
(optima:fail))
`(,x ,#(cdr (butlast args))))))
(match-ugly-funcall '(f (g "[" 1 3 5 4 8 "]")))
; => (G 1 3 5 4 8)
Then, we mimic Mathematica's Replace with this function, which takes a form and a list of rules to be tried. It is possible to pass a single rule (thanks to ensure-list). If a list of list of rules is given, a list of matches should be returned (to be done).
(defun match-replace (form rules &optional (levelspec '(0)))
(setf rules (ensure-list rules))
(multiple-value-bind (match-levelspec-p recurse-levelspec-p)
(optima:ematch levelspec
((list n1 n2) (if (some #'minusp (list n1 n2))
(optima:fail)
(values (lambda (d) (<= n1 d n2))
(lambda (d) (< d n2)))))
((list n) (if (minusp n)
(optima:fail)
(values (lambda (d) (= d n))
(lambda (d) (< d n)))))
(:infinity (values (constantly t) (constantly t))))
(labels
((do-replace (form depth)
(let ((result
(and (funcall match-levelspec-p depth)
(some (lambda (r) (funcall r form)) rules))))
(cond
(result (values result t))
((and (listp form)
(funcall recurse-levelspec-p depth))
(incf depth)
(do (newlist
(e (pop form) (pop form)))
((endp form) (values form nil))
(multiple-value-bind (result matchedp) (do-replace e depth)
(if matchedp
(return (values (nconc (nreverse newlist)
(list* result form)) t))
(push e newlist)))))
(t (values form nil))))))
(do-replace form 0))))
And a test:
(match-replace '(a b (f (x "[" 1 2 3 "]")) c d)
#'match-ugly-funcall
:infinity)
; => (A B (X 1 2 3) C D)
; T
In order to replace all expressions instead of the first matching one, use this instead:
(defun match-replace-all (form rules &optional (levelspec '(0)))
(setf rules (ensure-list rules))
(multiple-value-bind (match-levelspec-p recurse-levelspec-p)
(optima:ematch levelspec
((list n1 n2) (if (some #'minusp (list n1 n2))
(optima:fail)
(values (lambda (d) (<= n1 d n2))
(lambda (d) (< d n2)))))
((list n) (if (minusp n)
(optima:fail)
(values (lambda (d) (= d n))
(lambda (d) (< d n)))))
(:infinity (values (constantly t) (constantly t))))
(labels
((do-replace (form depth)
(let ((result
(and (funcall match-levelspec-p depth)
(some (lambda (r) (funcall r form)) rules))))
(cond
(result result)
((and (listp form)
(funcall recurse-levelspec-p depth))
(incf depth)
(mapcar (lambda (e) (do-replace e depth)) form))
(t form)))))
(do-replace form 0))))
Oh boy, how Mathematica manages to obfuscate everything by applying its renown NIH approach.
Basically, you're looking for a function to perform string replacement according to some pattern. In most languages, this is accomplished with regular expressions.
For instance, in Common Lisp using the cl-ppcre library it will look something like this:
(cl-ppcre:regex-replace-all
;; regular expression you match against with groups
"f\\[{(x[^ ]*), \"\\[\", ((y[^ ]* ?)+), \"\\]\"}\\]"
;; your string
"{f[{x, \"[\", y, \"]\"}], f#f[{x, \"[\", y, y2, \"]\"}]}"
;; substitution expression using groups 1 & 2
"\\1[\\2]")
Surely, you can write a specialized 20-line function for this problem of matching and substituting subtrees using subst and recursion, but if all that you want is cases similar to the presented one you can get away with a simple regex-based approach.

Nested FLET block inside LET block (and vice-versa)

Is it considered idiomatic or non-idiomatic to have a LET block nested inside aFLET/LABELS block ?
Again, I may be coming at this all wrong, but I'm trying to mimic the generic where block in Haskell (so I have a defun and I want to write code that uses certain temporary bindings for values and functions.
In case these are non-idiomatic (after all, I shouldn't expect to transfer over usage from one language to another), what's the right way to do this ?
E.g. something like (stupid example follows ...)
(defun f (x) (
(let* ((x 4)
(y (1+ x))
(flet ((g (x) (+ 2 x)))
(g y))))
You want to know if it's a difference of preference between:
(defun f (x)
(let* ((x 4) (y (1+ x)))
(flet ((g (x) (+ 2 x)))
(g y))))
and
(defun f (x)
(flet ((g (x) (+ 2 x)))
(let* ((x 4) (y (1+ x)))
(g y))))
?
It really doesn't matter which order you put flet/labels and let/let* in this case. It will produce the same result and your CL implementation might optimize your code such that the result would be the same anyway.
In a LISP-1 you would have put it in the same let and then the question would be if you should put the lambda first or last. Seems like taste to me.
The only case where there is a difference is when you are making calculations that are free variables in your function. Like this:
(defun f (x)
(let ((y (1+ x)))
(flet ((g (x) (+ 2 x y))) ; y is free, made in the let*
(g x))))
(f 5) ; ==> 13
Switching order is now impossible without moving logic since the function uses a free variable. You could put the let inside the definition of g like this:
(defun f (x)
(flet ((g (z) ; renamed to not shadow original x
(let* ((y (1+ x)))
(+ 2 z y)))
(g x))))
But imagine you used it with mapcar, reduce or recursion. Then it would have done the calculation for every iteration instead of once before the call. These are the cases that really matter.

"set! not an identifier" in Scheme

I am trying to modify the cdr of the car of an element of a list using set!, but I am getting an error: "set! not an identifier". Can anyone explain to me why this is happening? I am starting to work with objects by the way.
#lang racket
(define (multiset)
(let ((main-list '()))
(define (empty)
(eq? main-list '()))
(define (insert x)
(cond ((empty)
(set! main-list (cons (cons x 1) main-list)))
((= (car (car main-list)) x)
(begin (set! (cdr (car main-list))
(+ 1 (cdr (car main-list))))))
(else (cdr main-list))))
A multiset is represented as a list of pairs. For example, if I had a list '(1 1 1 2 2 2), the multiset representation would be '((1.3)(2.3))
The syntax of set! is
(set! <identifier> <expression>)
which is to say that the first form must be a symbol. In your code you are using:
(cdr (car main-list))
as the 'identifier' - hence the error.
Perhaps your background is CommonLisp and you are expecting set! to behave like setf? In Scheme there are separate functions for setting the 'car' and 'cdr' of a pair. Use set-car! and set-cdr!
> (define pair (cons 'car 'cdr))
> pair
(car . cdr)
> (set-car! pair 'foo)
> pair
(foo . cdr)
> (set-cdr! pair 'bar)
> pair
(foo . bar)
In R6RS (and probably R7RS) set-car! and set-cdr! can be found in the (rnrs mutable-pairs) library
GoZoner has given you the right explanation, but it is perfectly possible (and desirable) do avoid set! procedures. Here's an example of a procedure having the same result:
(define (rle lst)
(define (newpair c l res)
(if (> l 0) (cons (cons c l) res) res))
(let loop ((lst lst) (c #f) (l 0) (res '()))
(if (null? lst)
(reverse (newpair c l res))
(let ((n (car lst)))
(if (equal? c n)
(loop (cdr lst) c (add1 l) res)
(loop (cdr lst) n 1 (newpair c l res)))))))
such as
(rle '(1 1 1 2 2 2))
=> '((1 . 3) (2 . 3))

Scheme - list functions with filter

I am currently working on a homework assignment with MIT scheme, and have come across a few problems that are supposedly very short, though I'm a bit confused as to how to implement some of them.
One problem asks me to write a function that returns a list with all the integers removed. I did manage to solve that,
(define (f2a lst) (map (lambda(x) (remove number? x)) lst))
though I'm confused as to how I can rewrite it to not use remove, but rather use a filter.
*note: (f2a '(("a" 1 "b") (2 "c") (-1 "d") (-2))) returns '(("a" "b") ("c") ("d"))
The other two problems are ones to which I haven't found any solutions.
They ask me to write a function that returns a list with all positive odd and negative even integers removed. For example,
(f2b '(("a" 1 "b") (2 "c") (-1 "d") (-2)))
returns
(("a" "b") (2 "c") (-1 "d"))
I have some code down that is incorrect, but I feel shows how I have tried to approach solving this one:
(define (f2b lst)
(lambda(x)
(cond ((and (positive? x) (odd? x)) (filter x lst))
((and (negative? x) (even? x)) (filter x lst))
(else "this should never print"))))
The last problem simply asks for a function that returns a string consisting of all strings appended together in a list. (f2c '(("a" 1 "b") (2 "c") (-1 "d") (-2))) returns "abcd".
I almost managed to figure this one out, but got stuck when it kept returning strange values. This is the code I have:
(define (f2c lst)
(lambda(x)
(map (lambda (x) (filter string? x)) lst)
(list x))
(string-append (car lst) (cdr lst)))
In terms of higher-order syntax, I'm limited to map, filter, accumulate and sum. I am not asking for a direct answer, but rather some help for me to figure out what I need to do. What am I doing wrong with my code? Any assistance given with this is very much appreciated. Thank you.
The structure of the input and the desired output is identical in the first two problems; the only thing that differs is the predicate on when/when-not to remove an element. For the second case it would be:
(define (f2b lst)
(map (lambda (sublst)
(remove (lambda (x)
(and (number? x)
(or (and (positive? x) (odd? x))
(and (negative? x) (even? x)))))
sublst))
lst))
Since only the predicate differs you can generalize this as:
(define (f2x predicate)
(lambda (lst)
(map (lambda (sublst) (remove predicate sublst)) lst)))
(define f2a (f2x number?))
(define f2b (f2x (lambda (x)
(and (number? x)
(or (and (positive? x) (odd? x))
(and (negative? x) (even? x))))))
For your last problem, you can use the result of the first problem as:
(define (f2c lst)
(apply string-append (apply append (f2a list))))
Also, note that your syntax for f2b and f2a is incorrect. You are using
(define (func arg)
(lambda (x) ...))
which means that (func arg) returns a function which isn't what you want.

Resources