I have a method which returns class definitions:
(define (max-tracker%)
(let ([current-maximum 0])
(class object%
(init val) ; <--
...
(define held-value 0)
(set-val val)
(define/public (set-val newval) ; <--
(when (newval . >= . current-maximum)
(set! current-maximum newval))
(set! held-value newval))
...
)))
how do I bind a contract to the set-val method?
You can use the with-contract form, which lets you create arbitrary contract regions in expressions:
(define (max-tracker%)
(with-contract
max-tracker-procedure
#:result contract-expr
(class object% (init val) ...)))
This creates a contract region named max-tracker-procedure that exports exactly one anonymous value that must adhere to the contract specified in contract-expr. In this case you could specify a class/c contract. Multiple values and exports can be specified too, by using Racket's ability to return multiple values and using #:results (contract-expr ...) instead. Here's a simpler example demonstrating this:
(define test-value
(with-contract test
#:result (or/c integer? symbol?)
"neither int nor symbol - should break contract"))
Running this should give you:
broke its contract:
promised: (or/c integer? symbol?)
produced: "neither int nor symbol - should break contract"
in: (or/c integer? symbol?)
contract from: (region test)
blaming: (region test)
Combining this with class/c should give you what you're looking for.
EDIT
Here's an example closer to what you'd like:
(define (with-greeting class%)
(with-contract with-greeting
#:result (class/c [greet (->m string? string?)])
(class class%
(super-new)
(define/public (greet person)
(string-append "Hello, " person "!")))))
(define simple-greeter% (with-greeting object%))
(define simple-greeter (new simple-greeter%))
(send simple-greeter greet "Jack")
(send simple-greeter greet 'Jack)
Related
I am trying to define a class method like so:
#lang racket
(define foo% (class object%
(super-new)
(define/public plus-one (curry + 1))))
But this code produces the following error:
eval:2:0: class: bad form for method definition
According to the Racket documentation, it should be possible to define a method using the syntax (define/public id expr), so I don't understand why this isn't working.
There is an easy workaround by using the (define/public (id . formals) body ...+) syntax, of course, but I would like to understand why the current code isn't accepted.
In the documentation for class*, see the nonterminals named method-definition and method-procedure. They describe the constraints on a legal method definition. A paragraph later in the class docs says that each private, public, etc declaration must correspond to a method-definition. So it isn't a bug, it's the intended behavior.
The reason behind the behavior, by the way, is that Racket's class macro implements methods by rewriting the method's lambda (or case-lambda) expression(s) to add an implicit argument for this. The same argument is also implicitly used to access the object's public and private fields. Restricting method definitions to certain shapes makes it possible to find the right lambda expressions to adjust.
Here's one way of rewriting your example:
#lang racket
(define do-plus-one (curry + 1))
(define foo% (class object%
(super-new)
(define/public (plus-one n) (do-plus-one n)))
This has the following nice properties: do-plus-one is computed only once, and it doesn't take a field slot in each foo% object.
It might be a bug. Imagine we have the usuall way:
(define/public (plus-one n) (+ 1 n))
The define way with name and arguments in parentheses are sugar for a id and lambda and that works:
(define/public plus-one (lambda (n) (+ 1 n)))
I'm getting that (curry + 1) returns a similar lambda and that that object should be working, but it isn't.
The whole point with a class method is using the private fields from the object and none of them do that, however only curry version makes it obvious that it will not be able to since the resulting procedure won't be having the scope of the object.
If you imagined we used a private variable for the increment you couldn't use curry since it would cache it. eg. you can't replicate this:
(define increaser%
(class object%
(init inc)
(define increment inc)
(super-new)
(define/public (set-inc inc)
(set! increment inc))
(define/public (increase n)
(+ increment n))))
(define test (new increaser% [inc 2]))
(send test increase 1) ; ==> 3
(send test set-inc 3)
(send test increase 1) ; ==> 4
(define test2 (new increaser% [inc 21]))
(define value 13)
(map (lambda (obj) (send obj increase value)) (list test test2))
; ==> (16 34)
Can I mimic different constructors in CL?
To elaborate -- in, say, C++, I can make different constructors for the same class depending on what arguments are passed.
Can I do this with CLOS? Probably having different initialize-instances key args or something like that?
One approach to doing this is to have a secondary initialization method:
(defclass myclass ()
((s1 :initarg :s1 :accessor s1)))
(defgeneric initialize-myclass (dispatch class &key))
(defmethod initialize-instance :after ((c myclass) &rest args &key (dispatch 'normal)
&allow-other-keys)
(apply #'initialize-myclass dispatch c args))
(defmethod initialize-myclass ((dispatch (eql 'normal)) (class myclass) &key))
(defmethod initialize-myclass ((dispatch (eql 'special)) (class myclass)
&key x &allow-other-keys)
(print x))
Now you can say
(make-instance 'myclass :dispatch 'special ...)
For instance. Note this is not necessarily a good way of doing it, but it does work, and I've used it. Note also I may have got the keyword-argument defaulting wrong: I never remember where you need to say &allow-other-keys & where you don't, and where the right place to say it is.
The basic problem here is that we want an additional thing to dispatch on: initialize-instance can dispatch on the class of the object being defined, but that's all it can dispatch on. In particular it can't dispatch on one of its keyword arguments because you can't do that in CLOS. But we can take one of its keyword arguments (dispatch here) and 'bless' it as a positional argument to a secondary initialization generic function, which then can dispatch on that argument.
Well, initialize-instance is typically defined as an :after method to run some sort of post-processing once the instance has been initialized through make-instance. What you might do is use parametric polymorphism (dispatching on parameters) and have different methods initialize your instance based on the parameters supplied. Consider the following example:
CL-USER> (defclass my-class ()
((a :initarg :a
:accessor my-class-a)))
#<STANDARD-CLASS COMMON-LISP-USER::MY-CLASS>
CL-USER> (defmethod make-my-class ((a number))
(make-instance 'my-class :a (format nil "Look ma, a number ~a" a)))
#<STANDARD-METHOD COMMON-LISP-USER::MAKE-MY-CLASS (NUMBER) {1016445273}>
CL-USER> (defmethod make-my-class ((a string))
(make-instance 'my-class :a (format nil "Look ma, a string ~a" a)))
#<STANDARD-METHOD COMMON-LISP-USER::MAKE-MY-CLASS (STRING) {10166065C3}>
CL-USER> (make-my-class 10)
#<MY-CLASS {1016690E33}>
CL-USER> (my-class-a *)
"Look ma, a number 10"
CL-USER> (make-my-class "foo")
#<MY-CLASS {1016694CD3}>
CL-USER> (my-class-a *)
"Look ma, a string foo"
As you can see, the method make-my-class dispatches on its argument and initializes my-class accordingly.
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.
I like to build a REPL with my own datatypes, but I don't like to write all the same pattern functions over and over again.
So this is a nut, which bothers me.
I got my own set of primitive datatypes (define primitives '("mytrue" "myfalse" "mynumber" ...))
Also I have (define primitiveTesters (list "mytrue?" "myfalse?" "mynumber?" ... )
The problem now is, I just want to apply (map) or a macro to get the datatype? procedurces, which basically just checks if the car of record (mynumber . ( . )) exists.
So something similar like (mynumber? (car (mynumber.(1.))) => #t in the end. But for this I need (define mynumber? (lambda (...)(...))
My define-batching macro looks like this, but I just have no luck to infuse the <variable>.
(define-syntax define-batching
(syntax-rules ()
((_ value expr)(define value expr))
((_ value) value)
((_ value1 value2 ...) (begin (define value1 expr) (define-batching test2...)))
))
So have I reached a dead end of scheme ?
I've seen something similar, I think in Emacs Lisp.
What I am looking for in the end is:
(define checker '(audi? volkswagen? mercedes?))
(define datatype '(audi volkswagen mercedes))
(map define-checker checker datatype )
or
(define-checker (car checker) (car datatype))
If I understood the question right, you need a macro
to define your own type checkers?
Here is one way to do it:
(define-syntax define-checker
(syntax-rules ()
[(define-checker name tag)
(define (name object)
(and (list? object)
(not (null? object))
(eq? (car object) 'tag)))]))
(define-checker my-car? car)
(my-car? '(car audi black)) ; evaluates to #t
(my-car? '(truck ford pink)) ; evaluates to #f
Addendum:
If you write
(define checker '(audi? volkswagen? mercedes?))
(define datatype '(audi volkswagen mercedes))
the values will become available at runtime.
Therefore you need to a different approach.
You could for example write:
(define-checker+datatype (audi? audi) (volkswagen? volkswagen?))
Here is the code:
(define-syntax define-checker
(syntax-rules ()
[(define-checker name tag)
(define (name object)
(and (list? object)
(not (null? object))
(eq? (car object) 'tag)))]))
(define-syntax define-checkers+datatype
(syntax-rules ()
[(define-checkers+datatype (name tag) ...)
(begin
(define-checker name tag)
...)]))
(define-checkers+datatype (audi? audi) (wv? wv))
(audi? '(audi black))
define-syntax is hygienic, that means it cannot influence on parent environment, that means it cannot define symbols in it.
You may try to use er-, ir- macro-transformers which allow you to explicit renames symbols.
keywords to google in you scheme documentation are 'er-macro-transformet' and 'ir-macro-transformer'
I am trying to write a macro that defines a special class of data structure with associated functions.
I know this is possible; it is done multiple times in the core language itself.
As a specific example, how would I define the define-struct macro in Scheme itself. It needs to create make-struct, struct-<<field>>, etc functions.
I tried doing this using define, however, this only defines the function in the macro's lexical scope.
How can I actually define a function in a macro?
The key for an answer is datum->syntax. The basic idea is that you want to take some random data and turn it into a syntax -- in this case, turn a symbol into an identifier. An identifier is basically a symbol with some lexical information that (very roughly) indicates how it is bound. Using datum->syntax you can do exactly that: it expects an existing piece of syntax which is where it copies the binding from, and a datum (a symbol here) which is the value that is contained in the syntax wrapper.
Here's an example that demonstrates a define-struct-like tool using this:
#lang scheme
;; implements a defstruct-like macro that uses association lists
(define-syntax (defstruct-lite stx)
(syntax-case stx ()
[(defstruct-lite name field ...)
(let ([make-id
(lambda (template . ids)
(let ([str (apply format template (map syntax->datum ids))])
(datum->syntax stx (string->symbol str))))])
(with-syntax ([make-name (make-id "make-~a" #'name)]
[name? (make-id "~a?" #'name)]
[(arg ...) (generate-temporaries #'(field ...))]
[(name-field ...)
(map (lambda (f) (make-id "~a-~a" #'name f))
(syntax->list #'(field ...)))])
#'(begin
(define (make-name arg ...) (list 'name (cons 'field arg) ...))
(define (name? x) (and (pair? x) (eq? 'name (car x))))
(define (name-field x)
(and (name? x) (cdr (assq 'field (cdr x)))))
...)))]))
And here's an example of using it:
(defstruct-lite point x y)
(point-y (make-point 1 2))