[racket] How to get arity of make-object? Found answer
Sorry for being so late to the discussion, but I agree that something
like `class-constructor-arity` and `class-constructor-arity-includes?`
should be added to `racket/class`.
At Fri, 06 Jun 2014 05:24:36 +0400, Roman Klochkov wrote:
> Hm... But reading it's sources give me some clues.
>
> Now I have working dirty hack
>
> #lang racket/base
> (require racket/private/class-internal)
>
> (define (class-inits cls)
> (apply append
> (for/list ([c (in-vector (class-supers cls))])
> (class-init-args c))))
>
> It gives the list of class init arguments. Maybe someone also needs it.
> Thu, 5 Jun 2014 21:13:47 -0400 от Matthias Felleisen <matthias at ccs.neu.edu>:
> >
> >class/c doesn't check inits properly:
> >
> >>#lang racket
> >>
> >>(provide
> >> (contract-out
> >> [c% (class/c (init-field [x number?]))]))
> >>
> >>(define c%
> >> (class object%
> >> (field (x 10))
> >> (super-new)))
> >
> >and now run
> >
> >>Welcome to Racket v6.0.1.12.
> >>> (require "foo.rkt")
> >>> (new c%)
> >>(object:c% ...)
> >Okay more thinking to do -- Matthias
> >
> >
> >
> >
> >On Jun 5, 2014, at 8:49 PM, Roman Klochkov wrote:
> >>It is maybe closer.
> >>
> >>But inside define-binary-class I also doesn't know the total number of init
> arguments. Because library user may give any superclass. And I don't know, how
> to get init arguments (or arity for of make-object for a given class) without
> calling make-object and reading the error message.
> >>Lake in case
> >>(define base% (class (super-new) (init-field param1 param2)))
> >>(define-binary-class db base% ((a u1) (b u2)))
> >>
> >>Maybe the problem doesn't have a solution. But I see class/c, which has init
> and init-fields clauses. Somehow it checks them...
> >>
> >>Thu, 5 Jun 2014 16:36:16 -0400 от Matthias Felleisen < matthias at ccs.neu.edu >:
> >>>
> >>>Sorry I am so slow.
> >>>
> >>>Contracts are first-class values.
> >>>
> >>>You could modify define-binary-class so that it also creates and defines
> >>>a contract P that can be passed along to read-object. Then read-object
> >>>can use P like this:
> >>>
> >>>> #lang racket
> >>>>
> >>>> (provide
> >>>> a% a?
> >>>> b% b?
> >>>> (contract-out
> >>>> (read-object (->i ((c? contract?) (c% any/c))
> >>>> #:rest [l (c?) (lambda (x) (apply c? x))]
> >>>> (_ (c%) (is-a?/c c%))))))
> >>>>
> >>>> (define a% (class object% [init-field x] (super-new)))
> >>>> (define b% (class object% [init-field x y] (super-new)))
> >>>>
> >>>> (define a? (lambda x (and (= (length x) 1) (andmap number? x))))
> >>>> (define b? (lambda x (and (= (length x) 2) (andmap number? x))))
> >>>>
> >>>> (define (read-object __c c% . x)
> >>>> (apply make-object c% x))
> >>>
> >>>Then you get exactly what you want and pretty precise checking:
> >>>
> >>>> % !!
> >>>> racket
> >>>> Welcome to Racket v6.0.1.11.
> >>>> > (require "foo.rkt")
> >>>> foo.rkt:9:23: is-a/c?: unbound identifier in module
> >>>> in: is-a/c?
> >>>> context...:
> >>>> standard-module-name-resolver
> >>>> /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
> >>>> > (require "foo.rkt")
> >>>> foo.rkt:9:31: c%: unbound identifier in module
> >>>> in: c%
> >>>> context...:
> >>>> standard-module-name-resolver
> >>>> /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
> >>>> > (require "foo.rkt")
> >>>> > ( read-object b? b% 10 20 )
> >>>> (object:b% ...)
> >>>> > ( read-object b? b% 10 )
> >>>> read-object: contract violation
> >>>> expected: ...vn/2HtDP/foo.rkt:8:34
> >>>> given: '(10)
> >>>> in: the l argument of
> >>>> (->i
> >>>> ((c? contract?) (c% any/c))
> >>>> #:rest
> >>>> (l (c?) (lambda (x) (apply c? x)))
> >>>> (_ (c%) (is-a?/c c%)))
> >>>> contract from:
> >>>> /Users/matthias/svn/2HtDP/foo.rkt
> >>>> blaming: top-level
> >>>> at: /Users/matthias/svn/2HtDP/foo.rkt:7.5
> >>>> context...:
> >>>>
> /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
> raise-blame-error16
> >>>> arg-checker
> >>>> /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
> >>>> > ( read-object a? a% 10 )
> >>>> (object:a% ...)
> >>>> > ( read-object a? a% 10 20)
> >>>> read-object: contract violation
> >>>> expected: ...vn/2HtDP/foo.rkt:8:34
> >>>> given: '(10 20)
> >>>> in: the l argument of
> >>>> (->i
> >>>> ((c? contract?) (c% any/c))
> >>>> #:rest
> >>>> (l (c?) (lambda (x) (apply c? x)))
> >>>> (_ (c%) (is-a?/c c%)))
> >>>> contract from:
> >>>> /Users/matthias/svn/2HtDP/foo.rkt
> >>>> blaming: top-level
> >>>> at: /Users/matthias/svn/2HtDP/foo.rkt:7.5
> >>>> context...:
> >>>>
> /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
> raise-blame-error16
> >>>> arg-checker
> >>>> /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
> >>>
> >>>
> >>>
> >>>If you want to make sure that a? and a% come together, you can package them
> up in structs.
> >>>
> >>>If you just want to make sure that these contracts come from your binary
> class module, you can hide them in applicable structs or something like that.
> >>>
> >>>Am I getting closer? -- Matthias
> >>>
> >>>
> >>>
> >>>
> >>>On Jun 5, 2014, at 4:15 PM, Roman Klochkov < kalimehtar at mail.ru > wrote:
> >>>
> >>>> I don't create classes. I provide a function read-object, so user can do
> >>>>
> >>>> (require binary-class)
> >>>> (define base% (class (super-new) (init-field param1 param2)))
> >>>> (define-binary-class db base% ((a u1) (b u2)))
> >>>>
> >>>> (define data (read-object db my-file data-param1 data-param2)
> >>>>
> >>>> And I try to make a contract, so when he made an error in last call and
> wrote
> >>>>
> >>>> (define data (read-object db my-file data-param1)), then error message
> whould blame read-object, not `instantiate'
> >>>>
> >>>> Thu, 5 Jun 2014 16:08:39 -0400 от Matthias Felleisen <
> matthias at ccs.neu.edu >:
> >>>>
> >>>> Can't you use is-a?/c like this:
> >>>>
> >>>> > #lang racket
> >>>> >
> >>>> > (provide
> >>>> > a%
> >>>> > b%
> >>>> > (contract-out
> >>>> > (read-object (case->
> >>>> > [-> (is-a?/c a%) number? number?]
> >>>> > [-> (is-a?/c b%) number? number? number?]))))
> >>>> >
> >>>> > (define a% (class object% (super-new)))
> >>>> > (define b% (class object% (super-new)))
> >>>> >
> >>>> > (define read-object
> >>>> > (case-lambda
> >>>> > [(a x) x]
> >>>> > [(b x y) (+ x y)]))
> >>>>
> >>>>
> >>>> and use this module like this:
> >>>>
> >>>> > % racket
> >>>> > Welcome to Racket v6.0.1.11.
> >>>> > > (require "foo.rkt")
> >>>> > > (read-object (new a%) 10)
> >>>> > 10
> >>>> > > (read-object (new a%) 10 20)
> >>>> > read-object: contract violation
> >>>> > expected: (is-a?/c b%)
> >>>> > given: (object:a% ...)
> >>>> > in: the domain of
> >>>> > the 2nd case of
> >>>> > (case->
> >>>> > (-> (is-a?/c a%) number? number?)
> >>>> > (-> (is-a?/c b%) number? number? number?))
> >>>> > contract from:
> >>>> > /Users/matthias/svn/2HtDP/foo.rkt
> >>>> > blaming: top-level
> >>>> > at: /Users/matthias/svn/2HtDP/foo.rkt:7.5
> >>>> > context...:
> >>>> >
> /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
> raise-blame-error16
> >>>> > /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
> >>>> > > (read-object (new b%) 10 20)
> >>>> > 30
> >>>> > > (read-object (new b%) 10)
> >>>> > read-object: contract violation
> >>>> > expected: (is-a?/c a%)
> >>>> > given: (object:b% ...)
> >>>> > in: the domain of
> >>>> > the 1st case of
> >>>> > (case->
> >>>> > (-> (is-a?/c a%) number? number?)
> >>>> > (-> (is-a?/c b%) number? number? number?))
> >>>> > contract from:
> >>>> > /Users/matthias/svn/2HtDP/foo.rkt
> >>>> > blaming: top-level
> >>>> > at: /Users/matthias/svn/2HtDP/foo.rkt:7.5
> >>>> > context...:
> >>>> >
> /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
> raise-blame-error16
> >>>> > /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
> >>>>
> >>>>
> >>>>
> >>>> On Jun 5, 2014, at 3:19 PM, Roman Klochkov < kalimehtar at mail.ru > wrote:
> >>>>
> >>>> > (define (read-object binary-class in . args)
> >>>> > (send (apply make-object binary-class args) read in))
> >>>> >
> >>>> > read-object takes a class as a first arg, and additional arguments to
> make an object of that class.
> >>>> >
> >>>> > I can't make case-> because I don't know j,ject of what (user-defined)
> class will be created with the function by user of my library.
> >>>> >
> >>>> > This case is described in Racket Guide 7,3.9
> http://docs.racket-lang.org/guide/contracts-general-functions.html#%28part._cont
> racts-no-domain%29 , where recommended to use unconstrained-domain-> with
> procedure-arity-includes? , but it doesnt' work with make-object
> >>>> >
> >>>> > Thu, 5 Jun 2014 14:51:21 -0400 от Matthias Felleisen <
> matthias at ccs.neu.edu >:
> >>>> >
> >>>> > From what I understand now, you want a contract for a function that
> creates objects from a variable number of arguments. If you write your module
> interface like this,
> >>>> >
> >>>> > > #lang racket
> >>>> > >
> >>>> > > (provide
> >>>> > > (contract-out
> >>>> > > (read-object (case->
> >>>> > > [-> 'a number? number?]
> >>>> > > [-> 'b number? number? number?]))))
> >>>> > >
> >>>> > > (define read-object
> >>>> > > (case-lambda
> >>>> > > [(a x) x]
> >>>> > > [(b x y) (+ x y)]))
> >>>> >
> >>>> > you can get checked variable-arity behavior:
> >>>> >
> >>>> > > Welcome to Racket v6.0.1.11.
> >>>> > > > (require "foo.rkt")
> >>>> > > > (read-object 'a 10)
> >>>> > > 10
> >>>> > > > (read-object 'b 10 20)
> >>>> > > 30
> >>>> > > > (read-object 'b 10)
> >>>> > > read-object: contract violation
> >>>> > > expected: (quote a)
> >>>> > > given: 'b
> >>>> > > in: the domain of
> >>>> > > the 1st case of
> >>>> > > (case->
> >>>> > > (-> 'a number? number?)
> >>>> > > (-> 'b number? number? number?))
> >>>> > > contract from:
> >>>> > > /Users/matthias/svn/2HtDP/foo.rkt
> >>>> > > blaming: top-level
> >>>> > > at: /Users/matthias/svn/2HtDP/foo.rkt:5.5
> >>>> > > context...:
> >>>> > >
> /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
> raise-blame-error16
> >>>> > > /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
> >>>> > > > (read-object 'a 10 20)
> >>>> > > read-object: contract violation
> >>>> > > expected: (quote b)
> >>>> > > given: 'a
> >>>> > > in: the domain of
> >>>> > > the 2nd case of
> >>>> > > (case->
> >>>> > > (-> 'a number? number?)
> >>>> > > (-> 'b number? number? number?))
> >>>> > > contract from:
> >>>> > > /Users/matthias/svn/2HtDP/foo.rkt
> >>>> > > blaming: top-level
> >>>> > > at: /Users/matthias/svn/2HtDP/foo.rkt:5.5
> >>>> > > context...:
> >>>> > >
> /Users/matthias/plt/racket/collects/racket/contract/private/blame.rkt:143:0:
> raise-blame-error16
> >>>> > > /Users/matthias/plt/racket/collects/racket/private/misc.rkt:87:7
> >>>> >
> >>>> >
> >>>> > I think you can use ->i contracts inside of the case-> clauses if you
> need more precision.
> >>>> >
> >>>> > If I am still misunderstanding your question, sorry.
> >>>> >
> >>>> > -- Matthias
> >>>> >
> >>>> >
> >>>> >
> >>>> >
> >>>> > > >
> >>>> > > >
> >>>> > > > --
> >>>> > > > Roman Klochkov
> >>>> > >
> >>>> > >
> >>>> > >
> >>>> > > --
> >>>> > > Roman Klochkov
> >>>> >
> >>>> >
> >>>> >
> >>>> > --
> >>>> > Roman Klochkov
> >>>>
> >>>>
> >>>>
> >>>> --
> >>>> Roman Klochkov
> >>>
> >>
> >>
> >>--
> >>Roman Klochkov
> >
>
>
> --
> Roman Klochkov
> ____________________
> Racket Users list:
> http://lists.racket-lang.org/users