Lazy Racket on REPL - racket

I can change Racket from strict to lazy evaluation using #lang lazy, but that only works in a module. How can I use it in the REPL console?

To set the language in the REPL, you can use the -I flag. For example, to use the lazy language, run racket -iI lazy:
$ racket -iI lazy
Welcome to Racket v6.7.0.3.
> (define fibs
(list* 1 1 (map + fibs (cdr fibs))))
> fibs
#<promise:fibs>
> (list-ref fibs 10)
89

Related

in racket, eval works in the repl but not in a program

This does what I hoped:
$ racket
Welcome to Racket v8.3 [cs].
> (eval (list + 1 (list + 5 5)))
11
but this doesn't:
$ cat demo.rkt
#lang racket
(display (eval (list + 1 (list + 5 5))))
$ racket demo.rkt
?: function application is not allowed;
no #%app syntax transformer is bound
at: (#<procedure:+> 1 (#<procedure:+> 5 5))
context...:
What am I doing wrong?
I searched for the error, and it seems like this has never happened to anybody before
Well, I'll leave the question here with the answer in case anybody else searches for that error:
https://docs.racket-lang.org/guide/eval.html#%28part._namespaces%29
$ cat > demo.rkt
#lang racket
(define ns (make-base-namespace))
(display (eval (list + 1 (list + 5 5)) ns))
$ racket demo.rkt
11
It's all explained that it works in the repl but not a program.

Create suffixed numbers Racket

I'm trying to experiment with what I can do in Racket, and I want to suffix numbers with letters.
For this example, I'd simply like to represent 10000 as 10K, and 1000000 as 1M.
Is there way (with macros or otherwise) that I can expand 1M to:
(* 1 1000000)
Or something to that effect?
In Racket, things like 10K are identifiers, which normally would refer to variables. There are two ways to make them into numbers:
1: redefine what "undefined" identifiers mean
You can redefine what to do on an undefined identifier by defining a #%top macro.
#lang racket
(require syntax/parse/define
(only-in racket [#%top old-#%top]))
(define-syntax-parser #%top
[(_ . x:id)
#:when (id-has-a-k-at-the-end? #'x)
(transform-id-into-number #'x)]
[(_ . x)
#'(old-#%top . x)])
However, this has a subtle problem. If there are any identifiers or variables in your program with K's on the end, they could override any numbers that were written that way. You would need to be careful not to accidentally override something that was intended to be a number.
2: make a reader extension that turns them into numbers instead of identifiers
This will take more time, but it's closer to the "right way" to do this, since it avoids conflicts when variables happen to have K's on the end.
One of the easier ways to extend the reader is with a readtable. You can make a function that extends a readtable like this:
;; Readtable -> Readtable
(define (extend-readtable orig-rt)
;; Char InputPort Any Nat Nat Nat -> Any
(define (rt-proc char in src ln col pos)
....)
...
(make-readtable orig-rt
#f 'non-terminating-macro rt-proc
...))
To use this to define a #lang language, you need to put the reader implementation in your-language/lang/reader.rkt. Here that's number-with-k/lang/reader.rkt, where the number-with-k directory is installed as a single-collection package (raco pkg install path/to/number-with-k).
number-with-k/lang/reader.rkt
#lang racket
(provide (rename-out [-read read]
[-read-syntax read-syntax]
[-get-info get-info]))
(require syntax/readerr
syntax/module-reader)
;; Readtable -> Readtable
(define (extend-readtable orig-rt)
;; Char InputPort Any Nat Nat Nat -> Any
(define (rt-proc char in src ln col pos)
....)
...
(make-readtable orig-rt
#f 'non-terminating-macro rt-proc))
;; [X ... -> Y] -> [X ... -> Y]
(define ((wrap-reader rd) . args)
(parameterize ([current-readtable (extend-readtable (current-readtable))])
(apply rd args)))
(define-values [-read -read-syntax -get-info]
(make-meta-reader 'number-with-k
"language path"
lang-reader-module-paths
wrap-reader
wrap-reader
identity))
The main work goes into filling in the .... holes in the extend-readtable function. For example, you can make it recognize identifiers that end with K like this:
;; Readtable -> Readtable
(define (extend-readtable orig-rt)
;; Char InputPort Any Nat Nat Nat -> Any
(define (rt-proc char in src ln col pos)
(define v (read-syntax/recursive src in char orig-rt #f))
(cond
[(and (identifier? v) (id-has-a-k-at-the-end? v))
(transform-id-into-number v)]
[else
v]))
(make-readtable orig-rt
#f 'non-terminating-macro rt-proc))
Once this is done, and you have the number-with-k directory installed as a package, you should be able to use #lang number-with-k like this:
#lang number-with-k racket
(+ 12K 15)
; => 12015
The simplest to is to define the suffixes you need.
(define K 1000)
(define M 1000000)
Then write (* 3.14 M) for 3.14 millions.
As others mention, Racket supports scientific notation 3.14E6 is also 3.14 million.
Yet another alternative is to define functions K, M etc like:
(define (M x) (* x 1000000))
Then you can write
(M 3.14)
to mean 3.14 million.
Racket does already have built in support for this, kind of, via scientific notation:
1e6 ; 1000000.0 ("1M")
2e7 ; 20000000.0

Macro-defining macro in Racket?

In Common Lisp it is relatively easy to create a macro-defining macro. For example, the following macro
(defmacro abbrev (short long)
`(defmacro ,short (&rest args)
`(,',long ,#args)))
is a macro-defining macro, because it expands to another macro.
If we now put
(abbrev def defun)
in our program, we can write def instead of defun whenever we define a new function.
Of course, abbrev can be used for other things, too. For example, after
(abbrev /. lambda)
we can write (/. (x) (+ x 1)) instead of (lambda (x) (+ x 1)). Nice. (For detailed explanation of abbrev, see http://dunsmor.com/lisp/onlisp/onlisp_20.html)
Now, my questions are:
Can I write the macro-defining macros in Racket?
If I can, how to do that? (for example, how to write something similar to
abbrev macro in Racket?)
According to this part of the Racket Guide:
(define-syntax-rule (abbrev short long)
(define-syntax-rule (short body (... ...))
(long body (... ...))))
Quoting the above link:
The only non-obvious part of its definition is the (... ...), which
“quotes” ... so that it takes its usual role in the generated macro,
instead of the generating macro.
Now
(abbrev def define)
(abbrev /. lambda)
(def f (/. (x) (+ x 1)))
(f 3)
yields
4
FWIW, it works on Guile as well, so it's no Racket-specific thing.
ad 1. Yes.
ad 2. Your example can most easily be written
#lang racket
(define-syntax (abbrev stx)
(syntax-case stx ()
[(_ short long)
#'(define-syntax short (make-rename-transformer #'long))]))
(abbrev def define)
(def x 42)
x
The example above evaluates to 42.
I find that renaming can be done simply with define or let statements:
(define =? =)
(define lr list-ref)
or:
(let ((=? =)
(lr list-ref))
(println (lr '(1 2 3) 2))
(println (=? 1 2))
(println (=? 1 1)))
Output:
3
#f
#t
There seem to be no need for any macro for this purpose.

Does racket plt have an equivalent to Python's sha1.update()

I'd like to hash stdin in chunks using racket but can't find an equivalent to Python's hashlib's sha1.update function is there an equivalent or alternative?
Here is one way to do it:
#lang racket
(require (planet soegaard/digest:1:2/digest))
(define a #"The quick brown fox jumps ")
(define b #"over the lazy dog")
(define a+b (bytes-append a b))
(digest a+b 'sha1)
(define c (make-digest-context 'sha1))
(update-context c a)
(update-context c b)
(final-context->hex-string c)
The output is:
"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
You can find documentation on the digest collection here:
http://planet.racket-lang.org/package-source/soegaard/digest.plt/1/2/doc.txt
Use it something like this:
(define c (make-digest-context 'sha1))
(define in (open-input-file "foo"))
(let loop ()
(define chunk (read-bytes 4096 in))
(cond [(eof-object? chunk) (final-context->hex-string c)]
[else (update-context c chunk)
(loop)]))
Take a look at Greg Hendershott's sha library, which adds Racket support for SHA-1 and SHA-2 by providing a Racket interface to the OpenSSL implementation of SHA-1 and SHA-2.
(require sha)
(sha1 bstr) -> sha1?
bstr : bytes?
Although it doesn't have an update() procedure, as stated in Python's own documentation a call like this:
m.update(a); m.update(b)
Is equivalent to this:
m.update(a+b)

Racket - Having trouble with variables in macro

I'm currently trying to assign a variable to macro to store something:
(begin-for-syntax
(define a 0))
(define-syntax (foo stx)
(set! a (+ a 1))
(datum->syntax stx a))
(foo)
(foo)
(foo)
After compiling this piece of code, the repl showed "1 2 3". However, when I entered "(foo)" in the repl, the next number was "1" rather than "4" which was I expected.
1
2
3
> (foo)
1
It looked like the variable "a" was reset after the compiling had done. The same thing happened when I "require" this code in another module.
Is it possible to solve this problem?
I can't really explain why it doesn't work, but I feel that "hiding" a variable in phase level 1 might not exactly be the right approach. You can pretty much achieve the same with modules and without macros:
(module adder racket/base
(provide foo)
(define a 0)
(define (foo)
(set! a (add1 a))
a))
(require 'adder)
(foo)
(foo)
(foo)
prints
1
2
3
but then the sequence goes on at the REPL level:
> (foo)
4
> (foo)
5
Of course you can also use a simple closure:
(define foo
(let ((a 1))
(lambda ()
(begin0
a
(set! a (add1 a))))))
Racket has the separate compilation guarantee, which means that compilation of separate modules behaves consistently, because mutation and effects are reset just as if they were compiled separately, even when compiled together. Here the REPL behaves the same way.
One way to get around that for this particular situation is to have the macro expand to a begin-for-syntax that does the mutation instead of trying to do it in the macro transformer:
#lang racket
(begin-for-syntax
(define a 0))
(define-syntax (get-a stx)
(datum->syntax stx a))
(define-syntax (foo stx)
#'(begin
(begin-for-syntax
(set! a (+ a 1)))
(get-a)))
(foo)
(foo)
(foo)
Entering (foo) in REPL for this returns 4.
But for other modules, this is disallowed because set! cannot mutate a variable from a separate module.