Dependent contracts for structs in Racket - racket

Suppose I define a struct for a set with its "center".
(struct centered-set (center elems))
I want to guarantee the following conditions.
elems is a set.
center is an member of elems.
I can express the conditions with #:guard. Is there a way to express the same conditions as a contract?
For functions, ->i works as a combinator for that kind of dependent contracts. How to express dependent contracts for structs?

IIUC, contract-out doesn't support anything like that. However, you can simulate the functionality by providing the constructor and accessors manually with the contract attached:
#lang racket
(module foo racket
(provide (contract-out [bt (-> any/c any/c any/c (bst/c 1 10))]
[bt-val (-> (bst/c 1 10) any/c)]
[bt-left (-> (bst/c 1 10) any/c)]
[bt-right (-> (bst/c 1 10) any/c)]))
(define (bst/c lo hi)
(or/c #f
(struct/dc bt
[val (between/c lo hi)]
[left (val) #:lazy (bst/c lo val)]
[right (val) #:lazy (bst/c val hi)])))
(struct bt (val left right)))
(require 'foo)
(bt 11 #f #f)
It should be possible to write a provide transformer to automate this process.

Related

How to increment a Record Field using Scheme define-syntax macro

Given a Chez Scheme record with many numeric fields that are contantly being mutated by small increments and decrements, usually by one, is there a way to write a macro that can mutate a field value by passing it the field? The way I accomplish this now is something like the following REPL transcript:
Chez Scheme Version 9.5.4
Copyright 1984-2020 Cisco Systems, Inc.
> (define-record-type r (fields (mutable x) (mutable y)
;; and so on...
))
> (define my-r (make-r 3 5
;; and so on...
))
> (r-x-set! my-r (+ (r-x my-r) 1))
> my-r
#[#{r gak6l6ll8wuv7yd61kiomgudo-2} 4 5]
It would be nice to have a simple macro, say inc!, that could do the mutating increment/decrement operations on the fields in the record. I started with something like a Scheme version of Lisps incf and decf,
(define-syntax inc!
(syntax-rules ()
((_ x) (begin (set! x (+ x 1)) x))))
(inc! (r-x my-r)) ;; Syntax error
Which works for "normal" variables (and makes it easy to implement dec!), but it doesn't use the mechanism to set mutable record fields, r-x-set! in this case.
Is there an obvious way to write such a macro? One where you can just pass a reference to the record field without having to write something different for each field?
You can construct a -set! mutator from the given accessor. This can be done by converting the symbol for the accessor to a string and appending "-set!" to it. Then eval can be used to get the actual mutator procedure. Here is a macro that increments a specified field by some amount n:
(define-syntax increment-n!
(syntax-rules ()
[(_ (acc rec) n)
(let* ((acc-name (symbol->string (quote acc)))
(mut-name (string-append acc-name "-set!"))
(mut! (eval (string->symbol mut-name))))
(mut! rec (+ (acc rec) n)))]))
This can be used to create an inc! macro:
(define-syntax inc!
(syntax-rules ()
[(_ (acc rec)) (increment-n! (acc rec) 1)]))
But, it would be nice to be able to increment multiple fields at the same time; here are inc! and dec! macros that do that:
(define-syntax inc!
(syntax-rules ()
[(_ (acc rec) ...) (begin (increment-n! (acc rec) 1) ...)]))
(define-syntax dec!
(syntax-rules ()
[(_ (acc rec) ...) (begin (increment-n! (acc rec) -1) ...)]))
Sample interaction:
> my-r
#[#{r n5an6pxs3wvid36v2gvn8z9zo-5} 3 5 7]
> (inc! (r-x my-r))
> my-r
#[#{r n5an6pxs3wvid36v2gvn8z9zo-5} 4 5 7]
> (dec! (r-z my-r))
> my-r
#[#{r n5an6pxs3wvid36v2gvn8z9zo-5} 4 5 6]
> (inc! (r-x my-r) (r-y my-r) (r-z my-r))
> my-r
#[#{r n5an6pxs3wvid36v2gvn8z9zo-5} 5 6 7]
A Note on the Use of eval
The increment-n! macro constructs a symbol which has already been bound to a mutator procedure. That symbol could then be bound to mut! directly, but then when the expression (mut! rec (+ (acc rec) n)) is evaluated an exception would be raised since mut! now evaluates to a symbol, e.g., r-x-set!. We want mut! to evaluate to a procedure in a procedure call. By calling eval on the constructed symbol first we get the mutator procedure which is bound to that symbol, binding it to mut! instead of the symbol.
Here is a REPL interaction that illustrates the problem, and will hopefully help to clarify:
> (define f (string->symbol "+"))
> f
+
> (f 1 2)
Exception: attempt to apply non-procedure +
Type (debug) to enter the debugger.
> (define f (eval (string->symbol "+")))
> f
#<procedure +>
> (f 1 2)
3

How deterministic is Racket's evaluation order?

I would like to known how deterministic Racket's evaluation order is when set! is employed. More specifically,
Does #%app always evaluates its arguments from left to right?
If no, can the evaluation of different arguments be intertwined?
Take, for instance, this snippet:
#lang racket
(define a 0)
(define (++a) (set! a (add1 a)) a)
(list (++a) (++a)) ; => ?
Could the last expression evaluate to something different than '(1 2), such as '(1 1), '(2 2) or '(2 1)?
I failed to find a definite answer on http://docs.racket-lang.org/reference.
Unlike Scheme, Racket is guaranteed left to right. So for the example call:
(proc-expr arg-expr ...)
You can read the following in the Guide: (emphasis mine)
A function call is evaluated by first evaluating the proc-expr and all
arg-exprs in order (left to right).
That means that this program:
(define a 0)
(define (++a) (set! a (add1 a)) a)
(list (++a) (++a))
; ==> (1 2)
And it is consistent. For Scheme (2 1) is an alternative solution. You can force order by using bindings and can ensure the same result like this:
(let ((a1 (++ a)))
(list a1 (++ a)))
; ==> (1 2)

Does racket allow for function overloading?

I am new to Lisp-scheme and fairly new to the functional paradigm as a whole, and am currently doing an assignment which requires me to overload a function with the same name, but different sets of parameters in racket. Below is an example of what I'm trying to achieve:
#lang racket
(define (put-ball-in-box two-by-fours nails ball)
... )
(define (put-ball-in-box box ball)
... )
These are not the actual functions, but close enough. As implied, both functions would put a ball in a box, but one would assemble the box from its components first, then call the other. Obviously, when I try the above in DrRacket or using the command line, I get a module: duplicate definition for identifier ... error.
Is there a way to achieve this in racket?
Maybe the answer is right in front of me, but I have spent the last two hours searching for this and couldn't find anything, so would appreciate any pointers.
Thank you.
It doesn't in the usual sense of "writing another definition somewhere else."
It allows shadowing, which is defining a procedure with the same name as an imported procedure. Thus you can (define + ...) and your definition of + will hide the + from racket/base. If you want the original procedure, then you can do something like the following, where I define + to be either addition or string-appending.
#lang racket/base
(require (rename-in racket/base (+ base:+)))
(define (+ . args)
(if (andmap string? args)
(apply string-append args)
(apply base:+ args)))
Another thing you can do is use racket/match to have different behavior based on the shape of the argument.
#lang racket/base
(require racket/match)
(define (fib . arg)
(match arg
[(list n) (fib n 1 0)]
[(list 1 a b) a]
[(list 0 a b) b]
[(list n a b) (fib (sub1 n) (+ a b) a)]))
This second example still doesn't quite do what you want since you have to go to the original definition point and modify the match clauses. But it might be sufficient for your purposes.
A more complicated example would be to use custom syntax to create a define/overload form. But I think you'll find the racket/match solution to be best.
You have the concept of default values as in JS and PHP:
(define (fib n (a 0) (b 1))
(if (zero? n)
a
(fib (sub1 n) b (+ a b))))
(fib 10) ; ==> 55
Now if you had 5 optional parameters you need to order them and even pass some values just to be able to add a later one. To avoid that you can use keywords:
(define (test name #:nick [nick name] #:job [job "vacant"])
(list name nick job))
(test "sylwester" #:job "programmer")
; ==> ("sylwester" "sylwester" "programmer")
Now Racket has classes. You can call a method like (send object method args ...).
(define circle%
(class object%
(super-new)
(init-field radius)
(define/public (area)
(* radius radius 3.1415))))
(define cube%
(class object%
(super-new)
(init-field side)
(define/public (area)
(* side side))))
(define circle (new circle% [radius 7]))
(define cube (new cube% [side 7]))
(map
(lambda (o) (send o area))
(list circle cube))
; ==> (153.9335 49)
Notice that the two classes hasn't really commited to a joint interface with area so this is pure duck typing. Thus you can make a function that expects a class that implements a message and it doesn't need to worry about other aspects of the class at all.

(or/c #f <contract>) vs <contract>

According to the following example from the struct/dc entry in the Racket reference manual, the bst/c function below returns a contract such as every node in bt has its value bound between lo and hi.
(struct bt (val left right))
(define (bst/c lo hi)
(or/c #f
(struct/dc bt
[val (between/c lo hi)]
[left (val) #:lazy (bst lo val)]
[right (val) #:lazy (bst val hi)])))
That definition looks perfect to me, except for one thing: what is the purpose of the (or/c #f [...]) construct here ? Since #f is a constant that always evaluates to false, why not just remove the or/c logic altogether, and simply define bst/c as:
(define (bst/c lo hi)
(struct/dc bt
[val (between/c lo hi)]
[left (val) #:lazy (bst lo val)]
[right (val) #:lazy (bst val hi)]))
A binary search tree with a single value is constructed as:
(bst 42 #f #f)
Here #f is used to indicated that the left and right subtrees are empty.
Since we want the left and right subtrees also to be binary search trees, we need to include the value #f as a legal bst. The contract (or/c #f ...) says just that.

Racket: Using a macro across modules

In order to teach myself more advanced macros in racket, I set about creating a macro to increment a field in a mutable struct:
(increment! instance name field)
=>
(set-name-field instance (get-name-field instance))
I produced a macro that works, and decided it would be useful to share between multiple modules. Unfortunately, since the structure mutators are not in the scope of the module defining the macro, an expansion error occurs.
The following is a contrived example demonstrating the problem. I would like to know:
Did I write the macro code in idiomatic-racket style? Is this the correct approach?
How can I control the expansion of the macro, so that it operates in the presence of identifiers not found in it's original context?
Thanks.
#lang racket/load
(module util racket
(define-syntax increment!
(lambda (stx)
(syntax-case stx ()
[(increment! s sn fn i)
(with-syntax
([set! (string->symbol
(format "set-~a-~a!" (syntax-e #'sn) (syntax-e #'fn)))]
[get (string->symbol
(format "~a-~a" (syntax-e #'sn) (syntax-e #'fn)))])
#'(set! s (+ i (get s))))]
;; default increment of 1
[(increment! s sn fn) #'(increment! s sn fn 1)])))
(provide increment!)
)
(module bank racket
(require 'util)
(struct money (dollars pounds euros) #:mutable #:transparent)
(let ([m (money 0 50 20)])
(increment! m money pounds 100)
(increment! m money dollars)
m)
)
(require 'bank)
Results in
expand: unbound identifier in module in: set-money-pounds!
You can't do just that. The problem is that you're generating symbols with the correct names, but you just return the symbols as-is, which means that with-syntax gives them some default (and wrong) lexical context. Instead, you should use datum->syntax and give it the correct context.
Below is a revision of your code that works as you expect. To see more about it, see my recent blog post on the subject of unhygienic macros.
However, this is not a robust solution. What happens when the setters and getters have different names? A more robust solution would be to use the struct name and extract the right information from it (at syntax time, in the macro) -- see the manual for details on this. It's also good to ask questions about it on the mailing list, since there might be a better way to get what you want, or a better solution if you're looking for some dot-notation-like functionality.
#lang racket/load
(module util racket
(define-syntax increment!
(lambda (stx)
(syntax-case stx ()
[(increment! s sn fn i)
(let ([id (lambda (fmt)
(let ([str (format fmt (syntax-e #'sn) (syntax-e #'fn))])
(datum->syntax #'sn (string->symbol str))))])
(with-syntax ([set! (id "set-~a-~a!")]
[get (id "~a-~a")])
#'(set! s (+ i (get s)))))]
;; default increment of 1
[(increment! s sn fn) #'(increment! s sn fn 1)])))
(provide increment!))
(module bank racket
(require 'util)
(struct money (dollars pounds euros) #:mutable #:transparent)
(let ([m (money 0 50 20)])
(increment! m money pounds 100)
(increment! m money dollars)
m))
(require 'bank)