Why is racket macro's lambda not returning anything? - scheme

I'm trying to make a basic journal entry language in racket for a class on DSLs (specifically beautiful racket, the training version). I have a correct parser and reader, but I am having difficulty with my macros. Below is my expander code. I am trying to have my DSL be functional rather than imperative (I know I could have a global ledger value that I update, but it is not in the spirit of this project).
I have included the code for the important functions in this module. A lot of them are based off of this tutorial: https://beautifulracket.com/bf/a-functional-expander.html
Right now, when I run my code on this text:
[1920-02-19<equipment-20000><cash-10000,stock-10000>]
[2020-12-20<insurance-500><cash-500>]
I get this output from my display calls:
(#<date 1920-02-19> debits credits)()(#<date 2020-12-20> debits credits)#<void>#<void>
It looks like my lambda is not returning the updated ledger in my journal-entry macro. My knowledge isn't great when it comes to Racket, so I'm not sure what I'm doing wrong here. Any tips?
(define (fold-funcs apl ac-funcs)
(for/fold ([current-apl apl])
([ac-func (in-list ac-funcs)])
(ac-func current-apl)
(display current-apl)))
(define-macro (ac-line ENTRIES ...)
#'(begin
(define ledger empty)
(set! ledger (fold-funcs ledger (list ENTRIES ...)))
(display ledger)))
(provide ac-line)
(define-macro (journal-entry "[" INFO ... "]")
#'(lambda (ledger)
(define entry (list INFO ...))
(define dt (first entry))
(set! entry (rest entry))
(define d (first entry))
(set! entry (rest entry))
(define c (first entry))
(define e (list dt d c))
(display e)
(set! ledger (cons e ledger))
ledger
))
(provide journal-entry)

Related

Achieving name encapsulation while using 'define' over 'let'

In an attempt to emulate simple OOP in scheme (just for fun), I have caught myself repeating the following pattern over and over:
(define my-class ; constructor
(let ((let-for-name-encapsulation 'anything))
; object created from data is message passing interface
(define (this data)
(lambda (m)
(cond ((eq? m 'method1) (method1 data))
((eq? m 'method2) (method2 data))
(else (error "my-class: unknown operation error" m)))))
;
(define (method1 data)
(lambda (arg1 ...)
... )) ; code using internal 'data' of object
;
(define (method2 data)
(lambda (arg2 ...)
... ))
;
; returning three arguments constructor (say)
;
(lambda (x y z) (this (list 'data x y z)))))
I decided to wrap everything inside a let ((let-for-name-encapsulation ... so as to avoid leaking names within the global environment while still
being able to use the define construct for each internal function name, which enhances readability. I prefer this solution to the unsightly construct (let ((method1 (lambda (... but I am still not very happy because of the somewhat artificial let-for-name-encapsulation. Can anyone suggests something simple which would make the code look even nicer?. Do I need to learn macros to go beyond this?
I use that pattern often, but you don't actually need to define any variables:
(define binding
(let ()
(define local-binding1 expression)
...
procedure-expression)))
I've seen it in reference implementations of SRFIs so it's a common pattern. Basically it's a way to make letrec without the extra identation and lambdas. It can easily be made a macro to make it even flatter:
(define-syntax define/lexical
(syntax-rules ()
((_ binding body ...)
(define binding
(let ()
body ...)))))
;; test
(define/lexical my-class
(define (this data)
(lambda (m)
(cond ((eq? m 'method1) (method1 data))
((eq? m 'method2) (method2 data))
(else (error "my-class: unknown operation error" m)))))
(define (method1 data)
(lambda (arg1 ...)
... )) ; code using internal 'data' of object
(define (method2 data)
(lambda (arg2 ...)
... ))
;; returning three arguments constructor (say)
(lambda (x y z) (this (list 'data x y z))))
;; it works for procedures that return procedures as well
(define/lexical (count start end step)
(define ...)
(lambda ...))
Of course you could use macros to simplify your object system as well.

Is there a Scheme toString method for a procedure?

I want to be able to take a procedure and see what it looks like. Is this possible?
For example, let's say I have:
(define (some-func x)
(+ x 1))
What I want to do is apply some amazing function (say, stringify) to some-func and be able to look at its guts.
\> (stringify some-func)
"(lambda (x) (+ x 1))"
I haven't found any Racket libraries that do it. Can it be done?!
In R6RS, there is no sure way to determine if two procedures are equivalent; even an expression like (let ((p (lambda () 42))) (eqv? p p)) is not guaranteed to be true.
R7RS addresses that by using the concept of "location tags", where each lambda expression generates a unique location tag. Then eqv? works for procedures by comparing location tags: thus, (let ((p (lambda () 42))) (eqv? p p)) is true, and (eqv? (lambda () 42) (lambda () 42)) is false.
There is no reliable way to get the source of a procedure (many implementations macro-expand and compile the procedures, discarding the original source), and even if you could, you could not use it to compare if two procedures are "equal", because of closures (and that two procedures could have the same "source" but have their free variables bound to different things). For example, consider the two expressions (let ((x 1)) (lambda () x)) and (let ((x 2)) (lambda () x)). They have the same "source", but nobody in their right mind would claim that they are equivalent in any way.
Note, you could easily implement a define alternative to keep the source around. You don't avoid the lexical issues but, modulo that, you've got something with limited use.
(define name->source-mapping '())
(define (name->source name)
(cond ((assq name name->source-mapping) => cdr)
(else #f)))
(define (name->source-extend name source)
(set! name->source-mapping (cons (cons name source) name->source-mapping))
(define-syntax define-with-source
((_ (name args ...) body1 body2 ...)
(define name
(begin (name->source-mapping-extend 'name '(lambda (args ...) body1 body2 ...))
name->source-mapping))
(lambda (args ...) body1 body2 ...)))))
[Above does not replace (define name value) syntax; consider the above an example only.]

How to implement call-with-values to match the values example in R5RS

R5RS says...
Values might be defined as follows:
(define (values . things)
(call-with-current-continuation
(lambda (cont) (apply cont things))))
It doesn’t, however, say how call-with-values might be implemented if values were implemented this way. So, if values is implemented this way, how would call-with-values be implemented?
(This came up because I was trying to get some code that used call-with-values to work with TinyScheme, which doesn’t support it. I managed by faking values and call-with-values with lists, but—when I saw this in R5RS—I wanted to know if this might be a better workaround.)
Kent Dybvig defines call/cc, values and call-with-values thusly:
(define call/cc call/cc)
(define values #f)
(define call-with-values #f)
(let ((magic (cons 'multiple 'values)))
(define magic?
(lambda (x)
(and (pair? x) (eq? (car x) magic))))
(set! call/cc
(let ((primitive-call/cc call/cc))
(lambda (p)
(primitive-call/cc
(lambda (k)
(p (lambda args
(k (apply values args)))))))))
(set! values
(lambda args
(if (and (not (null? args)) (null? (cdr args)))
(car args)
(cons magic args))))
(set! call-with-values
(lambda (producer consumer)
(let ((x (producer)))
(if (magic? x)
(apply consumer (cdr x))
(consumer x))))))
The short answer is: You can't
The nifty implementation of values does not change the fact that there is no way to implement the other procedures if you don't have any of them to poke at the values. If you had one way to peek then you could implement the others with that.
(+ (values 4 5))
(apply + (values 4 5))
Doesn't work and that's why you need those other primitives.
When that said. There is no difference between returning more values and returning lists with values since the difference is optimization. You could make a macro that treats both of them as a binding and then the way you use them would be the same. The difference in performance is some pointer jumping and some consing which is reasonable fast for any lisp implementation. Heres a minimalistic implementation that will work given your code is correct:
(define values list)
(define (call-with-values producer consumer)
(apply consumer (producer)))

How do I get the functions put and get in SICP, Scheme, Exercise 2.78 and on

I am trying to do exercise 2.78 in SICP, but the functions put and get are unknown. I have tried multiple languages, like pretty big, racket, r5rs, mit-scheme, mzscheme, etc. I even downloaded the SICP support (http://www.neilvandyke.org/sicp-plt/), to no avail. How can I get these functions to work?
Yes, I found SICP a little annoying sometimes because of stuff like this. Functions that are assumed to exist but don't actually exist make it harder to try to the examples. I wrote my own (get) and (put) like so (this was in GNU guile):
(define global-array '())
(define (make-entry k v) (list k v))
(define (key entry) (car entry))
(define (value entry) (cadr entry))
(define (put op type item)
(define (put-helper k array)
(cond ((null? array) (list(make-entry k item)))
((equal? (key (car array)) k) array)
(else (cons (car array) (put-helper k (cdr array))))))
(set! global-array (put-helper (list op type) global-array)))
(define (get op type)
(define (get-helper k array)
(cond ((null? array) #f)
((equal? (key (car array)) k) (value (car array)))
(else (get-helper k (cdr array)))))
(get-helper (list op type) global-array))
Probably a naive implementation from the perspective of later in the book, but fairly simple and worked fine.
There is an implementation of put and get by Eli Bendersky.
These functions could be implemented using builtin Basic Hash Table Operations. Here is my modified version of Eli's code to work properly with MIT-Scheme Release 9.1.1.
(define *op-table* (make-hash-table))
(define (put op type proc)
(hash-table/put! *op-table* (list op type) proc))
(define (get op type)
(hash-table/get *op-table* (list op type) '()))
UPDATED:
I've found bug with above mentioned code after time. Empty lists are interpreted as true in conditional clauses by Scheme, so correct get implementation should be following:
(define (get op type)
(hash-table/get *op-table* (list op type) #f))
If you use Racket programming language please use these:
(define *op-table* (make-hash))
(define (put op type proc)
(hash-set! *op-table* (list op type) proc))
(define (get op type)
(hash-ref *op-table* (list op type) '()))
In subsection Creating local tables of 3.3.3 Representing Tables, there is an implementation.
mit-scheme has a built-in global table that you can use.
http://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/The-Association-Table.html
simply define get and put to:
(define get 2d-get)
(define put 2d-put!)

Seeking Simply Scheme idioms for Dr. Scheme

I'm working my way through SICP, using both the Ableson/Sussman
lectures and the Berkeley 61A lectures, which are far more my
speed. I'd like to do some of the Berkeley homework, but need the
definitions for sentence, butfirst, butlast and so forth. It looks like at one time there was a simply scheme language built in to Dr. Scheme, but version 4.1.5, the most recent, doesn't have it. From Planet PLT
I thought I could simply add (require (planet "simply-scheme.ss" ("dyoo"
"simply-scheme" 1 0))) in my definitions window. I get
require: PLaneT
could not find the requested package: Server had no matching package:
No package matched the specified criteria
I tried grabbing the simply.scm file from here
and pasted it into my Dr Scheme definitions window, but it doesn't work:
In Advanced Student mode, I get
read: illegal use of "."
For the line (lambda (string . args) in the following code.
(define whoops
(let ((string? string?)
(string-append string-append)
(error error)
(cons cons)
(map map)
(apply apply))
(define (error-printform x)
(if (string? x)
(string-append "\"" x "\"")
x))
(lambda (string . args)
(apply error (cons string (map error-printform args))))))
In R5RS I get
set!: cannot mutate module-required identifier in: number->string
(line 7 of the following code)
(if (char=? #\+ (string-ref (number->string 1.0) 0))
(let ((old-ns number->string)
(char=? char=?)
(string-ref string-ref)
(substring substring)
(string-length string-length))
(set! number->string
(lambda args
(let ((result (apply old-ns args)))
(if (char=? #\+ (string-ref result 0))
(substring result 1 (string-length result))
result)))))
'no-problem)
Advanced Student will never really work for you unless you're following examples that were designed for it. Most books and examples will assume R5RS or something like it. I would recommend using the Pretty Big language, as that includes both R5RS, as well as the PLT require syntax, and a few other things.
In order to use the Simply Scheme package from PLaneT, you will need to use the new require syntax (you can find this on the package listing page; it looks like the docs for the package haven't been updated):
(require (planet dyoo/simply-scheme:1:2/simply-scheme))
Following up; the Simply Scheme support library for Racket can be found at:
http://planet.plt-scheme.org/display.ss?package=simply-scheme.plt&owner=dyoo
I did some light documentation updates in http://planet.plt-scheme.org/package-source/dyoo/simply-scheme.plt/2/1/planet-docs/manual/index.html.

Resources