I hope you can help me a little. For a homework I am supposed to code a function, that checks if an expression corresponds to a certain structure definition using pattern matching.
These are the definitions:
(define-struct literal (value))
(define-struct addition (lhs rhs))
(define-struct subtraction (lhs rhs))
(define-struct multiplication (lhs rhs))
(define-struct division (lhs rhs))
My code starts as follows:
; An Expression is one of:
; - (make-literal Number)
; - (make-addition Expression Expression)
; - (make-subtraction Expression Expression)
; - (make-multiplication Expression Expression)
; - (make-division Expression Expression)
; interp. abstract syntax tree of arithmetic expressions
(define EXPRESSION-1 (make-literal 42))
(define EXPRESSION-2
(make-addition (make-literal 4) (make-multiplication (make-literal 5) (make-literal 8))))
(define EXPRESSION-3
(make-division (make-subtraction (make-literal 11) (make-literal 7)) (make-literal 2)))
; Any -> Boolean
; checks whether e is an Expression
(check-expect (expression? EXPRESSION-1) #true)
(check-expect (expression? EXPRESSION-2) #true)
(check-expect (expression? (make-literal "42")) #false)
(define (expression? e)
(match e
[(and (literal?) (number? literal-value)) #true]
[(and (addition?) (number? addition-lhs) (addition-rhs)) #true]
[substraction? #true]
[multiplication? #true]
[division? #true]
[... #false]
))
The reason I am doing it this way is because I have to check if the expression is of the sctructure and I also have to make sure that the elements of that structure are nothing but numbers as the second test would fail then.
But somehow my way doesn't work as the test for the EXPRESSION-1 and EXPRESSION-2 already fail and I cannot get my head straigth, why...
I left the four lower lines as they were in the beginning, because I want to focus on the line for addition as I expect it would be a simple repetition of the line for 'addition?'.
How would you proceed to get that right?
Also, would you recommend to outsource this check for the numbers as elements of the structure into a seperate funtion?
Cheers!
Edit:
Now just as I thought I got it straight, I am struggling with the next task where I beleive it must work almost the same way as Atharva Shukla suggested below. The task is to translate the expression into an s-expression, so e.g from (make-addition (make-literal 1) (make-literal 2)) to '(+ 1 2) also using pattern matching.
; Expression -> S-Expression
; converts an expression into the corresponding S-Expression
(check-expect (expr->sexpr EXPRESSION-1) '42)
(check-expect (expr->sexpr EXPRESSION-2) '(+ 4 (* 5 8)))
(check-expect (expr->sexpr EXPRESSION 3) '(/ (- 11 7) 2))
(check-expect (expr->sexpr (make-addition (make-literal 1) (make-literal 2))
'(+ 1 2))
(define (expr->sexpr e)
(match e
[(literal value) 'value]
[(addition lhs rhs) '(+ (addition lhs) (addition rhs))]
[(subtraction lhs rhs) '(- (subtraction lhs) (subtraction rhs))]
[...]
[...]
))
The field names specified in the pattern will be bound in their respective clauses. So no need for predicates.
(define (expression? e)
(match e
[(literal v) (number? v)]
[(addition l r) (and (expression? l) (expression? r))]
[(subtraction l r) (and (expression? l) (expression? r))]
[(multiplication l r) (and (expression? l) (expression? r))]
[(division l r) (and (expression? l) (expression? r))]
[_ #false]))
The last clause is a wildcard i.e. evaluated the RHS for any value.
The same RHS for clauses 2-5 could be abstracted as follows:
(define (expression? e)
(match e
[(literal v) (number? v)]
[(or (addition l r) (subtraction l r)
(multiplication l r) (division l r))
(and (expression? l) (expression? r))]
[_ #false]))
However I prefer the first version more because it mirrors the Expression definition.
Edit 12/1/20:
It would be similar to the previous example but we construct the list as we go.
(check-expect (compile-expression EXPRESSION-1) 42)
(check-expect (compile-expression EXPRESSION-2) `(+ 4 (* 5 8)))
(check-expect (compile-expression EXPRESSION-3) `(/ (- 11 7) 2))
(define (compile-expression e)
(match e
[(literal v) v]
[(addition l r) (list '+ (compile-expression l) (compile-expression r))]
[(subtraction l r) (list '- (compile-expression l) (compile-expression r))]
[(multiplication l r) (list '* (compile-expression l) (compile-expression r))]
[(division l r) (list '/ (compile-expression l) (compile-expression r))]
[_ (error "Not an Expression")]))
I prefer this version because it allows you to create more complex structures easily:
(define (compile-expression e)
(match e
[(literal v) v]
[(addition l r) `(+ ,(compile-expression l) ,(compile-expression r))]
[(subtraction l r) `(- ,(compile-expression l) ,(compile-expression r))]
[(multiplication l r) `(* ,(compile-expression l) ,(compile-expression r))]
[(division l r) `(/ ,(compile-expression l) ,(compile-expression r))]
[_ (error "Not an Expression")]))
You can learn more about Quote, Quasiquote, and Unquote here.
Related
I am currently learning miniKanren by The Reasoned Schemer and Racket.
I have three versions of minikanren implementation:
The Reasoned Schemer, First Edition (MIT Press, 2005). I called it TRS1
https://github.com/miniKanren/TheReasonedSchemer
PS. It says that condi has been replaced by an improved version of conde which performs interleaving.
The Reasoned Schemer, Second Edition (MIT Press, 2018). I called it TRS2
https://github.com/TheReasonedSchemer2ndEd/CodeFromTheReasonedSchemer2ndEd
The Reasoned Schemer, First Edition (MIT Press, 2005). I called it TRS1*
https://docs.racket-lang.org/minikanren/
I have did some experiments about the three implementations above:
1st experiment:
TRS1
(run* (r)
(fresh (x y)
(conde
((== 'a x) (conde
((== 'c y) )
((== 'd y))))
((== 'b x) (conde
((== 'e y) )
((== 'f y)))))
(== `(,x ,y) r)))
;; => '((a c) (a d) (b e) (b f))
TRS2
(run* (x y)
(conde
((== 'a x) (conde
((== 'c y) )
((== 'd y))))
((== 'b x) (conde
((== 'e y) )
((== 'f y))))))
;; => '((a c) (a d) (b e) (b f))
TRS1*
(run* (r)
(fresh (x y)
(conde
((== 'a x) (conde
((== 'c y) )
((== 'd y))))
((== 'b x) (conde
((== 'e y) )
((== 'f y)))))
(== `(,x ,y) r)))
;; => '((a c) (b e) (a d) (b f))
Notice that, in the 1st experiment, TRS1 and TRS2 produced the same result, but TRS1* produced a different result.
It seems that the conde in TRS1 and TRS2 use the same search algorithm, but TRS1* use a different algorithm.
2nd experiment:
TRS1
(define listo
(lambda (l)
(conde
((nullo l) succeed)
((pairo l)
(fresh (d)
(cdro l d)
(listo d)))
(else fail))))
(define lolo
(lambda (l)
(conde
((nullo l) succeed)
((fresh (a)
(caro l a)
(listo a))
(fresh (d)
(cdro l d)
(lolo d)))
(else fail))))
(run 5 (x)
(lolo x))
;; => '(() (()) (() ()) (() () ()) (() () () ()))
TRS2
(defrel (listo l)
(conde
((nullo l))
((fresh (d)
(cdro l d)
(listo d)))))
(defrel (lolo l)
(conde
((nullo l))
((fresh (a)
(caro l a)
(listo a))
(fresh (d)
(cdro l d)
(lolo d)))))
(run 5 x
(lolo x))
;; => '(() (()) ((_0)) (() ()) ((_0 _1)))
TRS1*
(define listo
(lambda (l)
(conde
((nullo l) succeed)
((pairo l)
(fresh (d)
(cdro l d)
(listo d)))
(else fail))))
(define lolo
(lambda (l)
(conde
((nullo l) succeed)
((fresh (a)
(caro l a)
(listo a))
(fresh (d)
(cdro l d)
(lolo d)))
(else fail))))
(run 5 (x)
(lolo x))
;; => '(() (()) ((_.0)) (() ()) ((_.0 _.1)))
Notice that, in the 2nd experiment, TRS2 and TRS1* produced the same result, but TRS1 produced a different result.
It seems that the conde in TRS2 and TRS1* use the same search algorithm, but TRS1 use a different algorithm.
These makes me very confusion.
Could someone help me to clarify these different search algorithms in each minikanren implementation above?
Very thanks.
---- ADD A NEW EXPERIMENT ----
3nd experiment:
TRS1
(define (tmp-rel y)
(conde
((== 'c y) )
((tmp-rel-2 y))))
(define (tmp-rel-2 y)
(== 'd y)
(tmp-rel-2 y))
(run 1 (r)
(fresh (x y)
(conde
((== 'a x) (tmp-rel y))
((== 'b x) (conde
((== 'e y) )
((== 'f y)))))
(== `(,x ,y) r)))
;; => '((a c))
However, run 2 or run 3 loops.
If I use condi instead of conde, then run 2 works but run 3 still loop.
TRS2
(defrel (tmp-rel y)
(conde
((== 'c y) )
((tmp-rel-2 y))))
(defrel (tmp-rel-2 y)
(== 'd y)
(tmp-rel-2 y))
(run 3 r
(fresh (x y)
(conde
((== 'a x) (tmp-rel y))
((== 'b x) (conde
((== 'e y) )
((== 'f y)))))
(== `(,x ,y) r)))
;; => '((b e) (b f) (a c))
This is OK, except that the order is not as expected.
Notice that (a c) is at the last now.
TR1*
(define (tmp-rel y)
(conde
((== 'c y) )
((tmp-rel-2 y))))
;;
(define (tmp-rel-2 y)
(== 'd y)
(tmp-rel-2 y))
(run 2 (r)
(fresh (x y)
(conde
((== 'a x) (tmp-rel y))
((== 'b x) (conde
((== 'e y) )
((== 'f y)))))
(== `(,x ,y) r)))
;; => '((a c) (b e))
However, run 3 loops.
Your first experiment in TRS1 implementation, in Prolog ("and" is ,, "or" is ;) and in an equivalent symbolic Logic notation ("and" is *, "or" is +), proceeds as if
ex1_TRS1( R )
:= ( X=a , ( Y=c ; Y=d ) ; X=b , ( Y=e ; Y=f ) ) , R=[X,Y] ;; Prolog
== ( {X=a} * ({Y=c} + {Y=d}) + {X=b} * ({Y=e} + {Y=f}) ) * {R=[X,Y]} ;; Logic
== ( ({X=a}*{Y=c} + {X=a}*{Y=d}) + ({X=b}*{Y=e} + {X=b}*{Y=f}) ) * {R=[X,Y]} ;; 1
----( ( <A> + <B> ) + ( <C> + <D> ) )------------
----( <A> + <B> + <C> + <D> )------------
== ( {X=a}*{Y=c} + {X=a}*{Y=d} + {X=b}*{Y=e} + {X=b}*{Y=f} ) * {R=[X,Y]} ;; 2
== {X=a}*{Y=c}*{R=[X,Y]} ;; Distribution
+ {X=a}*{Y=d}*{R=[X,Y]}
+ {X=b}*{Y=e}*{R=[X,Y]}
+ {X=b}*{Y=f}*{R=[X,Y]}
== {X=a}*{Y=c}*{R=[a,c]}
+ {X=a}*{Y=d}*{R=[a,d]} ;; Reconciling
+ {X=b}*{Y=e}*{R=[b,e]}
+ {X=b}*{Y=f}*{R=[b,f]}
;; Reporting
== {R=[a,c]} + {R=[a,d]} + {R=[b,e]} + {R=[b,f]}
;; => ((a c) (a d) (b e) (b f))
The * operation must perform some validations, so that {P=1}*{P=2} ==> {}, i.e. nothing at all, since those two assignments are inconsistent with one another. It can also perform simplifications by substitution, going from {X=a}*{Y=c}*{R=[X,Y]} to {X=a}*{Y=c}*{R=[a,c]}.
Evidently, in this implementation, ((<A> + <B>) + (<C> + <D>)) == (<A> + <B> + <C> + <D>) (as seen in the ;; 1 --> ;; 2 step). Apparently it is the same in TRS2:
ex1_TRS2( [X,Y] ) := ( X=a, (Y=c ; Y=d) ; X=b, (Y=e ; Y=f) ).
;; => ((a c) (a d) (b e) (b f))
But in TRS1* the results' ordering is different,
ex1_TRS1_star( R ) := ( X=a, (Y=c ; Y=d) ; X=b, (Y=e ; Y=f) ), R=[X,Y].
;; => ((a c) (b e) (a d) (b f))
so there it must have been ((<A> + <B>) + (<C> + <D>)) == (<A> + <C> + <B> + <D>).
Up to the ordering, the results are the same.
There's no search algorithm in the book, just the solutions streams' mixing algorithm. But since the streams are lazy it achieves the same thing.
You can go through the rest in the same manner and discover more properties of + in each particular implementation.
After several days of research, I think I have been able to answer this question.
1. Concept clarification
First of all, I'd like to clarify some concepts:
There are two well-known models of non-deterministic computation: the stream model and the two-continuations model. Most of miniKanren implementations use the stream model.
PS. The term "backtracking" generally means depth-first search (DFS), which can be modeled by either the stream model or the two-continuations model. (So when I say "xxx get tried", it doesn't mean that the underlying implementation have to use two-continuations model. It can be implemented by stream model, e.g. minikanren.)
2. Explain the different versions of the conde or condi
2.1 conde and condi in TRS1
TRS1 provides two goal constructors for non-deterministic choice, conde and condi.
conde uses DFS, which be implemented by MonadPlus of stream.
The disadvantage of MonadPlus is that it is not fair. When the first alternative offers an infinite number of results, the second alternative is never tried. It making the search incomplete.
To solve this incomplete problem, TRS1 introduced condi which can interleave the two results.
The problem of the condi is that it can’t work well with divergence (I mean dead loop with no value). For example, if the first alternative diverged, the second alternative still cannot be tried.
This phenomenon is described in the Frame 6:30 and 6:31 of the book. In some cases you may use alli to rescue, see Frame 6:32, but in general it still can not cover all the diverged cases, see Frame 6:39 or the following case: (PS. All these problems do not exist in TRS2.)
(define (nevero)
(all (nevero)))
(run 2 (q)
(condi
((nevero))
((== #t q))
((== #f q))))
;; => divergence
Implementation details:
In TRS1, a stream is a standard stream, i.e. lazy-list.
The conde is implemented by mplus:
(define mplus
(lambda (a-inf f)
(case-inf a-inf
(f)
((a) (choice a f))
((a f0) (choice a (lambdaf# () (mplus (f0) f)))))))
The condi is implemented by mplusi
:(define mplusi
(lambda (a-inf f)
(case-inf a-inf
(f)
((a) (choice a f))
((a f0) (choice a (lambdaf# () (mplusi (f) f0)))))) ; interleaving
2.2 conde in TRS2
TRS2 removed the above two goal constructors and provided a new conde .
The conde like the condi, but only interleaving when the first alternative is a return value of a relation which be defined by defref. So it is actually more like the old conde if you won't use defref.
The conde also fixed the above problem of condi.
Implementation details:
In TRS2, a stream is not a standard stream.
As the book says that
A stream is either the empty list, a pair whose cdr is a stream, or a suspension.
A suspension is a function formed from (lambda () body) where (( lambda () body)) is a stream.
So in TRS2, streams are not lazy in every element, but just lazy at suspension points.
There is only one place to initially create a suspension, i.e. defref:
(define-syntax defrel
(syntax-rules ()
((defrel (name x ...) g ...)
(define (name x ...)
(lambda (s)
(lambda ()
((conj g ...) s)))))))
This is reasonable because the "only" way to produce infinite results or diverge is recursive relation. It also means that if you use define instead of defrel to define a relation, you will encounter the same problem of conde in TRS1 (It is OK for finite depth-first search).
Note that I had to put quotation marks on the "only" because most of the time we will use recursive relations, however you still can produce infinite results or diverge by mixing Scheme's named let, for example:
(run 10 q
(let loop ()
(conde
((== #f q))
((== #t q))
((loop)))))
;; => divergence
This diverged because there is no suspension now.
We can work around it by wrapping a suspension manually:
(define-syntax Zzz
(syntax-rules ()
[(_ g) (λ (s) (λ () (g s)))]))
(run 10 q
(let loop ()
(Zzz (conde
((== #f q))
((== #t q))
((loop)))) ))
;; => '(#f #t #f #t #f #t #f #t #f #t)
The conde is implemented by append-inf:
(define (append-inf s-inf t-inf)
(cond
((null? s-inf) t-inf)
((pair? s-inf)
(cons (car s-inf)
(append-inf (cdr s-inf) t-inf)))
(else (lambda () ; interleaving when s-inf is a suspension
(append-inf t-inf (s-inf))))))
2.3 conde in TRS1*
TRS1* originates from the early paper "From Variadic Functions to Variadic Relations A miniKanren Perspective". As TRS2, TRS1* also removed the two old goal constructors and provided a new conde.
The conde like the conde in TRS2, but only interleaving when the first alternative itself is a conde.
The conde also fixed the above problem of condi.
Note that there is no defref in TRS1*. Therefore if the recursive relations are not starting from conde, you will encounter the same problem of condi in TRS1. For example,
(define (nevero)
(fresh (x)
(nevero)))
(run 2 (q)
(conde
((nevero))
((== #t q))
((== #f q))))
;; => divergence
We can work around this problem by wrapping a conde manually:
(define (nevero)
(conde
((fresh (x)
(nevero)))))
(run 2 (q)
(conde
((nevero))
((== #t q))
((== #f q))
))
;; => '(#t #f)
Implementation details:
In TRS1*, the stream is the standard stream + suspension.
(define-syntax conde
(syntax-rules ()
((_ (g0 g ...) (g1 g^ ...) ...)
(lambdag# (s)
(inc ; suspension which represents a incomplete stream
(mplus*
(bind* (g0 s) g ...)
(bind* (g1 s) g^ ...) ...))))))
(define-syntax mplus*
(syntax-rules ()
((_ e) e)
((_ e0 e ...) (mplus e0 (lambdaf# () (mplus* e ...)))))) ; the 2nd arg of the mplus application must wrap a suspension, because multiple clauses of a conde are just syntactic sugar of nested conde with 2 goals.
It also means that the named let loop problem above does not exist in TRS1*.
The conde is implemented by the interleaving mplus:
(define mplus
(lambda (a-inf f)
(case-inf a-inf
(f)
((a) (choice a f))
((a f^) (choice a (lambdaf# () (mplus (f) f^))))
((f^) (inc (mplus (f) f^)))))) ; interleaving when a-inf is a suspension
; assuming f must be a suspension
Note that although the function is named mplus, it is not a legal MonadPlus because it does not obey MonadPlus law.
3. Explain these experiments in the question.
Now I can explain these experiments in the question.
1st experiment
TRS1 => '((a c) (a d) (b e) (b f)) , because conde in TRS1 is DFS.
TRS2 => '((a c) (a d) (b e) (b f)) , because conde in TRS2 is DFS if no defref involved.
TRS1* => '((a c) (b e) (a d) (b f)), because conde in TRS1* is interleaving (the outmost conde make the two innermost condes interleaving).
Note that if we replace conde with condi in TRS1, the result will be the same as TRS1*.
2nd experiment
TRS1 => '(() (()) (() ()) (() () ()) (() () () ())) , because conde in TRS1 is DFS. The second clause of conde in listo is never tried, since when (fresh (d) (cdro l d) (lolo d) is binded to the first clause of conde in listo it offers an infinite number of results.
TRS2 => '(() (()) ((_0)) (() ()) ((_0 _1))) , because now the second clause of conde in listo can get tried. listo and lolo being defined by defrel means that they will potentially create suspensions. When append-inf these two suspensions, each takes a step and then yield control to the other.
TRS1* => '(() (()) ((_.0)) (() ()) ((_.0 _.1)), is the same as TRS2, except that suspensions are created by conde.
Note that replacing conde with condi in TRS1 will not change the result. If you want to get the same result as TRS2 or TRS1*, wrap alli at the second clause of conde.
3rd experiment
Note that as #WillNess said in his comment of the question:
BTW I didn't know you could write (define (tmp-rel-2 y) (== 'd y) (tmp-rel-2 y)) like that, without any special minikanren form enclosing the two goals...
Yes, the 3rd experiment about TRS1 and TRS1* has a mistake:
(define (tmp-rel-2 y) ; <--- wrong relation definition!
(== 'd y)
(tmp-rel-2 y))
Unlike TRS2, TRS1 and TRS1* have no build-in defrel, so the define form is from Scheme, not minikaren.
We should use a special minikanren form enclosing the two goals.
Therefore,
For TRS1, we should change the definition to
(define (tmp-rel-2 y)
(all (== 'd y)
(tmp-rel-2 y)))
For TRS1*, there is no all constructor, but we can use (fresh (x) ...) to work around it
(define (tmp-rel-2 y)
(fresh (x)
(== 'd y)
(tmp-rel-2 y)))
I made this mistake because I was not familiar with minikanren before.
However, this mistake won't affect the final result, and the explanation below for TRS1 and TRS1* are suitable for both the wrong definition and the correct definition.
TRS1 => '((a c)), because conde in TRS1 is DFS. The tmp-rel diverges at tmp-rel-2.
Note that replacing conde with condi and (run 2 ...), we will get '((a c) (b e)). This because condi can interleave. However, it still cannot print the third solution (b f) because condi can’t work well with divergence.
TRS2 => '((b e) (b f) (a c)) , because TRS2 can archive complete search if we use defrel to define relation.
Note that the final result is '((b e) (b f) (a c)) instead of '((a c) (b e) (b f)) because in TRS2, a suspension only initially be created by defrel. If we expect '((a c) (b e) (b f)), we can wrap the suspension manually:
(define-syntax Zzz
(syntax-rules ()
[(_ g) (λ (s) (λ () (g s)))]))
(run 3 r
(fresh (x y)
(conde
((== 'a x) (tmp-rel y))
((== 'b x) (Zzz (conde ; wrap a suspension by Zzz
((== 'e y) )
((== 'f y))))))
(== `(,x ,y) r)))
;; => '((a c) (b e) (b f))
TRS1* => '((a c) (b e)), because in TRS1*, suspensions be wrapped at condes .
Note that it still cannot print the third solution (b f) because tmp-rel-2 does not be wrapped in conde, so no suspension is created here. If we expect '((a c) (b e) (b f)), we can wrap the suspension manually:
(define (tmp-rel-2 y)
(conde ((== 'd y) (tmp-rel-2 y)))) ; wrap a suspension by conde
4. Conclusion
All in all, minikanren is not one language but families of languages. Each minikanren implementation may have its own hack. There may be some corner cases which have slightly different behaviors in different implementations. Fortunately, minikanren is easy to understand. When encountering these corner cases, we can solve them by reading the source code.
5. References
The Reasoned Schemer, First Edition (MIT Press, 2005)
From Variadic Functions to Variadic Relations - A miniKanren Perspective
The Reasoned Schemer, Second Edition (MIT Press, 2018)
µKanren: A Minimal Functional Core for Relational Programming
Backtracking, Interleaving, and Terminating Monad Transformers
Here is a Scheme code to produce the permutations of a list of elements:
(define (remove x lst) (cond
((null? lst) '())
((= x (car lst)) (remove x (cdr lst)))
(else (cons (car lst) (remove x (cdr lst))))))
(define (permute lst) (cond
((= (length lst) 1) (list lst))
(else (apply append
(map (lambda (i)
(map (lambda (j) (cons i j))
(permute (remove i lst)))) lst)))))
I do understand each part of the code if we take the code apart, but what I can’t understand is how this all leads to generating the permutations?
Let’s say we take the list ‘(a b), how does it generate ‘(a b) and ‘(b a)?
We start by removing a from the list and b stays, but where is written that you now have to cons a to b? b is a single element, but in my interpretation of the code, b will also be removed and there is nothing left…
I would read the main part like this (in the order indicated by numbers)
(map (lambda (i) ;(1) for each i in...
(map (lambda (j) ;(3) for each j in...
(cons i j)) ;(6) append i to front (of this shorter permutation)
(permute ;(4) ...the list of all permutations...
(remove i lst)))) ;(5) ...of the input list with i removed
lst) ;(2) ... the input list
(TL;DR: the verbal explanation is at the very end of this answer.)
Let's try following the definitions with let*-rewrites. The definitions are
(define (remove x lst) (cond
((null? lst) '())
((= x (car lst)) (remove x (cdr lst)))
(else (cons (car lst) (remove x (cdr lst))))))
(define (permute lst) (cond
((= (length lst) 1) (list lst))
(else (apply append
(map (lambda (i)
(map (lambda (j) (cons i j))
(permute (remove i lst)))) lst)))))
We try
(permute '(a b))
≡
(let* ((lst '(a b)))
(apply append
(map (lambda (i)
(map (lambda (j) (cons i j))
(permute (remove i lst))))
lst)))
≡
(let* ((lst '(a b))
(r (map (lambda (i)
(map (lambda (j) (cons i j))
(permute (remove i lst))))
lst)))
(apply append r))
≡
(let* ((lst '(a b))
(i1 'a)
(r1 (map (lambda (j) (cons i1 j))
(permute (remove i1 lst))))
(i2 'b)
(r2 (map (lambda (j) (cons i2 j))
(permute (remove i2 lst))))
(r (list r1 r2)))
(apply append r))
≡
(let* ((lst '(a b))
(i1 'a)
(t1 (permute (remove i1 lst)))
(r1 (map (lambda (j) (cons i1 j)) t1))
(i2 'b)
(t2 (permute (remove i2 lst)))
(r2 (map (lambda (j) (cons i2 j)) t2))
(r (list r1 r2)))
(apply append r))
≡
(let* ((i1 'a)
(t1 (permute '(b)))
(r1 (map (lambda (j) (cons i1 j)) t1))
(i2 'b)
(t2 (permute '(a)))
(r2 (map (lambda (j) (cons i2 j)) t2))
(r (list r1 r2)))
(apply append r))
≡
(let* ((i1 'a)
(t1 '( (b) ))
(r1 (map (lambda (j) (cons i1 j)) t1))
(i2 'b)
(t2 '( (a) ))
(r2 (map (lambda (j) (cons i2 j)) t2))
(r (list r1 r2)))
(apply append r))
and so we get
(let* ((r1 (map (lambda (j) (cons 'a j)) '( (b) )))
(r2 (map (lambda (j) (cons 'b j)) '( (a) )))
(r (list r1 r2)))
(apply append r))
≡
(let* ((r1 (list (cons 'a '(b))))
(r2 (list (cons 'b '(a))))
(r (list r1 r2)))
(apply append r))
≡
(let* ((r1 (list '(a b)))
(r2 (list '(b a)))
(r (list r1 r2)))
(apply append r))
≡
(let* ((r1 '((a b)))
(r2 '((b a)))
(r (list r1 r2)))
(apply append r))
≡
(apply append (list '((a b)) '((b a))))
≡
( append '((a b)) '((b a)) )
≡
'( (a b) (b a) )
Follow the same technique if you need to convince yourself in the validity of the intermediate results.
In hindsight, we could simplify it a bit more aggressively, like
(let* ((lst '(a b))
(i1 'a)
(r1 (map (lambda (j) (cons i1 j))
(permute (remove i1 lst))))
(i2 'b)
(r2 (map (lambda (j) (cons i2 j))
(permute (remove i2 lst))))
(r (list r1 r2)))
(apply append r))
≡
(let* ((lst '(a b))
(i1 'a)
(t1 (permute (remove i1 lst)))
(r1 (map (lambda (j) (cons i1 j)) t1))
(i2 'b)
(t2 (permute (remove i2 lst)))
(r2 (map (lambda (j) (cons i2 j)) t2)))
(apply append (list r1 r2)))
≡
(let* ((t1 (permute '(b)))
(r1 (map (lambda (j) (cons 'a j)) t1))
(t2 (permute '(a)))
(r2 (map (lambda (j) (cons 'b j)) t2)))
(append r1 r2))
≡
(let* ((r1 (map (lambda (j) (cons 'a j)) '( (b) )))
(r2 (map (lambda (j) (cons 'b j)) '( (a) )))
)
(append r1 ; one row for each elt '( a
r2 ; of the input list, b
)) ; spliced in place by append )
etc., in the end revealing the structure of the computation in the more visually apparent manner:
for each element of the input list,
find all the permutations of the remainder,
prepend that element to each of them,
and join together the results from thus processing each element in the input list, by appending all those results together.
(thus justifying my other, pseudocode-based answer here).
(apply append (map f xs)) == (flatmap f xs).
Re-writing your code in an equational pattern-matching pseudocode,
remove x [x, ...ys] = remove x ys ; skip this x, and go on removing
; ( consider skipping just this one occurrence instead:
; = ys )
remove x [y, ...ys] = [y, ...remove x ys] ; (or else x /= y, so keep this y)
remove x [] = [] ; until the list is exhausted
permute [x] = [[x]]
permute xs =
xs ; ( with (xs |> f) == (f xs) )
|> flatmap (x => ; for each x in xs,
permute (remove x xs) ; for each permutation p of xs w/o x,
|> map (p => [x, ...p]) ) ; prepend x to p and
; splice the results in place of x
Is this clearer?
No? So, let's see how permute [a,b] is calculated.
First, what is permute [a]?
permute [a] = ...
( permute [x] = [[x]] )
... = [[a]]
(it doesn't matter how we call the first element of a single-element list, it's still its first and only element). Similarly,
permute [b] = ...
( permute [x] = [[x]] )
... = [[b]]
OK, but how does it help us see what's the result of permute [a,b]? Let's work with it step by step:
permute [ a, b ] =
;; for each x in (xs==[a,b])
;; a b ; <<- the value of x
;; remove x from xs
;; [b] [a] ; <<- xs with x removed
;; prepend x to each permutation of the above
;; [[ b]] [[ a]] ; <<- permutations
;; [[a,b]] [[b,a]] ; <<- prefixed with x
;; splice them in by `apply append`
[ [a,b] , [b,a] ]
So then, permute [b,c] == [[b,c],[c,b]], etc. And, armed with this knowledge,
permute [ a, b, c ] =
;; for each x in (xs==[a,b,c])
;; remove x from xs
;; [b,c] [a,c] [a,b]
;; prepend x to each permutation of the above
;; [[ b,c],[ c,b]] [[ a,c],[ c,a]] [[ a,b],[ b,a]]
;; [[a,b,c],[a,c,b]] [[b,a,c],[b,c,a]] [[c,a,b],[c,b,a]]
;; splice them in by `apply append`
[ [a,b,c],[a,c,b], [b,a,c],[b,c,a], [c,a,b],[c,b,a] ]
Is that clearer?
I am writing a program in scheme that takes in regular scheme notation ex: (* 5 6) and returns the notation that you would use in any other language ex: (5 * 6)
I have my recursive step down but I am having trouble breaking out into my base case.
(define (infix lis)
(if (null? lis) '()
(if (null? (cdr lis)) '(lis)
(list (infix (cadr lis)) (car lis) (infix(caddr lis))))))
(infix '(* 5 6))
the error happens at the (if (null? lis)) '(lis)
the error message is:
mcdr: contract violation
expected: mpair?
given: 5
>
why is it giving me an error and how can I fix this?
Right now your infix function is assuming that its input is always a list. The input is not always a list: sometimes it is a number.
A PrefixMathExpr is one of:
- Number
- (list BinaryOperation PrefixMathExpr PrefixMathExpr)
If this is the structure of your data, the code should follow that structure. The data definition has a one-of, so the code should have a conditional.
;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
(cond
[(number? p) ???]
[(list? p) ???]))
Each conditional branch can use the sub-parts from that case of the data definition. Here, the list branch can use (car p), (cadr p), and (caddr p).
;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
(cond
[(number? p) ???]
[(list? p) (.... (car p) (cadr p) (caddr p) ....)]))
Some of these sub-parts are complex data definitions, in this case self-references to PrefixMathExpr. Those self-references naturally turn into recursive calls:
;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
(cond
[(number? p) ???]
[(list? p) (.... (car p) (infix (cadr p)) (infix (caddr p)) ....)]))
Then fill in the holes.
;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
(cond
[(number? p) p]
[(list? p) (list (infix (cadr p)) (car p) (infix (caddr p)))]))
This process for basing the structure of the program on the structure of the data comes from How to Design Programs.
Mistake
(infix '(* 5 6))
; =
(list (infix (cadr '(* 5 6))) (car '(* 5 6)) (infix (caddr '(* 5 6))))
; =
(list (infix 5) '* (infix (caddr 6)))
; = ^^^^^^^^^
; |
; |
; v
(if ...
...
(if (null? (cdr 5)) ; <-- fails here
...
...))
Solution
First, you need to define the structure of the data you're manipulating:
; OpExp is one of:
; - Number
; - (cons Op [List-of OpExp])
; Op = '+ | '* | ...
In english: it's either a number or an operator followed by a list of other op-expressions.
We define some examples:
(define ex1 7)
(define ex2 '(* 1 2))
(define ex3 `(+ ,ex2 ,ex1))
(define ex4 '(* 1 2 3 (+ 4 3 2) (+ 9 8 7)))
Now we follow the structure of OpExp to make a "template":
(define (infix opexp)
(if (number? opexp)
...
(... (car opexp) ... (cdr opexp) ...)))
Two cases:
The first case: what to do when we just get a number?
The second case: first extract the componenet:
(car opexp) is the operator
(cdr opexp) is a list of operands of type OpExp
Refining the template:
(define (infix opexp)
(if (number? opexp)
opexp
(... (car opexp) ... (map infix (cdr opexp)) ...)))
Since we have a a list of op-exps, we need to map a recursive call on all of them. All we need to do is make the operator infix at the top-level.
We use a helper that intertwines the list with the operator:
; inserts `o` between every element in `l`
(define (insert-infix o l)
(cond ((or (null? l) (null? (cdr l))) l) ; no insertion for <= 1 elem lst
(else (cons (car l) (cons o (insert-infix o (cdr l)))))))
and finally use the helper to get the final version:
; converts OpExp into infix style
(define (infix opexp)
(if (number? opexp)
opexp
(insert-infix (car opexp) (map infix (cdr opexp)))))
We define respective results for our examples:
(define res1 7)
(define res2 '(1 * 2))
(define res3 `(,res2 + ,res1))
(define res4 '(1 * 2 * 3 * (4 + 3 + 2) * (9 + 8 + 7)))
And a call of infix on ex1 ... exN should result in res1 ... resN
my task is to make this to test to run:
(test (run "{+ {2 1} {3 4}}") '(5 6 4 5))
(test (run "{+ {- {+ 1 3} 2} {10 -10}}") '(12 -8))
The source code i have so far looks like that
#lang plai
(require (for-syntax racket/base) racket/match racket/list racket/string
(only-in mzlib/string read-from-string-all))
;; build a regexp that matches restricted character expressions, can use only
;; {}s for lists, and limited strings that use '...' (normal racket escapes
;; like \n, and '' for a single ')
(define good-char "(?:[ \t\r\na-zA-Z0-9_{}!?*/<=>:+-]|[.][.][.])")
;; this would make it awkward for students to use \" for strings
;; (define good-string "\"[^\"\\]*(?:\\\\.[^\"\\]*)*\"")
(define good-string "[^\"\\']*(?:''[^\"\\']*)*")
(define expr-re
(regexp (string-append "^"
good-char"*"
"(?:'"good-string"'"good-char"*)*"
"$")))
(define string-re
(regexp (string-append "'("good-string")'")))
(define (string->sexpr str)
(unless (string? str)
(error 'string->sexpr "expects argument of type <string>"))
(unless (regexp-match expr-re str)
(error 'string->sexpr "syntax error (bad contents)"))
(let ([sexprs (read-from-string-all
(regexp-replace*
"''" (regexp-replace* string-re str "\"\\1\"") "'"))])
(if (= 1 (length sexprs))
(car sexprs)
(error 'string->sexpr "bad syntax (multiple expressions)"))))
(test/exn (string->sexpr 1) "expects argument of type <string>")
(test/exn (string->sexpr ".") "syntax error (bad contents)")
(test/exn (string->sexpr "{} {}") "bad syntax (multiple expressions)")
;; WAE abstract syntax trees
(define-type WAE
[num (listof number?)]
[add (left WAE?) (right WAE?)]
[sub (left WAE?) (right WAE?)]
[with (name symbol?) (init WAE?) (body WAE?)]
[id (name symbol?)])
; parse-sexpr : sexpr -> WAE
;; to convert s-expressions into WAEs
(define (parse-sexpr sexp)
(match sexp
[(? number?) (num sexp)]
[(list '+ l r) (add (parse-sexpr l) (parse-sexpr r))]
[(list '- l r) (sub (parse-sexpr l) (parse-sexpr r))]
[(list 'with (list x i) b) (with x (parse-sexpr i) (parse-sexpr b))]
[(? symbol?) (id sexp)]
[else (error 'parse "bad syntax: ~a" sexp)]))
parses a string containing a WAE expression to a WAE AST
(define (parse str)
(parse-sexpr (string->sexpr str)))
substitutes the second argument with the third argument in the first argument, as per the rules of substitution; the resulting expression contains no free instances of the second argument
(define (subst expr from to)
(type-case WAE expr
[num (n) expr]
[add (l r) (add (subst l from to) (subst r from to))]
[sub (l r) (sub (subst l from to) (subst r from to))]
[id (name) (if (symbol=? name from) (num to) expr)]
[with (bound-id named-expr bound-body)
(with bound-id
(subst named-expr from to)
(if (symbol=? bound-id from)
bound-body
(subst bound-body from to)))]))
evaluates WAE expressions by reducing them to numbers
(define (eval expr)
(type-case WAE expr
[num (n) n]
[add (l r) (+ (eval l) (eval r))]
[sub (l r) (- (eval l) (eval r))]
[with (bound-id named-expr bound-body)
(eval (subst bound-body
bound-id
(eval named-expr)))]
[id (name) (error 'eval "free identifier: ~s" name)]))
; run : string -> listof number
;; evaluate a WAE program contained in a string
(define (run str)
(eval (parse str)))
bin-op : (number number -> number) (listof number or number) (listof number or number) -> (listof number))
applies a binary numeric function on all combinations of numbers from the two input lists or numbers, and return the list of all of the results
(define (bin-op op ls rs)
(define (helper l rs)
;; f : number -> number
(define (f n) (op l n))
(map f rs))
(if (null? ls)
null
(append (helper (first ls) rs) (bin-op op (rest ls) rs))))
Can someone please give me an idea how to change my functions to make the tests above work?
Thank you in advance.
I have created a function that takes a list as input and returns either a list or a atom. I want to apply this function to a deep list, starting with the inner lists, then finish once the function has been run on the outer list.
Can somebody give me some direction on this?
A sample input would be (a b (c (d e))) z) the function should compute on (d e) first with a result of say f. then the function should compute on (c f) with a result of say g then similarly on (a b g z) to produce an output of h.
An example function could be:
(define sum
(lambda (l)
(if (not (pair? l))
0
(+ (car l) (sum (cdr l))))))
Where input would be (1 2 (3 4) 5) > 15
Assuming your example transformation, expressed as a Scheme procedure:
(define (transform lst)
(case lst
(((d e)) 'f)
(((c f)) 'g)
(((a b g z)) 'h)
(else (error (~a "wot? " lst)))))
then what you are looking for seems to be
(define (f lst)
(transform
(map (lambda (e)
(if (list? e) (f e) e))
lst)))
Testing:
> (f '(a b (c (d e)) z))
'h
Here is an example:
(define product
(lambda (l)
(cond
[(number? l) l]
[(pair? l) (* (product (car l)) (product (cdr l)))]
[else 1])))
> (product '(1 2 (3 4) 5))
120