On Monday, September 5, 2016 at 10:54:57 PM UTC+5:30, Matthias Felleisen wrote:
> The easiest and proper fix is to write typed macros for typed modules. Below 
> is a naive but straightforward solution. It would be better if 
> define-memoized fished out the type declaration for f and used it to add 
> domain types for arg-s...
> 
> #lang typed/racket
> 
> (require (for-syntax syntax/parse))
> 
> (: memoize (All (r a ...)
>                 (-> (-> a ... a r)
>                     (-> a ... a r))))
> (define (memoize fn)
>   (let ([store : (HashTable Any r) (make-hash)])
>     (define (memfn . [args : a ... a])
>       (hash-ref store args
>                 (lambda ()
>                   (let ([result : r (apply fn args)])
>                     (hash-set! store args result)
>                     result))))
>     memfn))
> 
> (: fibo (-> Integer Integer))
> (define fibo (memoize (lambda ([n : Integer])
>                         (if (<= n 1)
>                             1
>                             (+ (fibo (- n 1))
>                                (fibo (- n 2)))))))
> 
> (define-syntax (define-memoized stx)
>   (syntax-parse stx ;; I didn’t get the ‘:’ syntax right the first time, so I 
> gave up on that 
>     [(_ (fn-name:id {arg t} ...) Tresult body ...)
>      #'(begin
>          (: fn-name (-> t ... Tresult))
>          (define fn-name (memoize (lambda ({arg : t} ...) body ...))))]))
> 
> 
> (define-memoized (fib {n Integer}) Integer
>   (if (<= n 1)
>       1
>       (+ (fib (- n 1))
>          (fib (- n 2)))))
> 
> (fib 10)
> 
> 
> 
> > On Sep 5, 2016, at 3:11 AM, Sourav Datta <[email protected]> wrote:
> > 
> > Another day, another typed racket question!
> > 
> > I was experimenting with memoize library in Racket and noticed that it does 
> > not always work with typed racket functions (or, may be I was not 
> > 'require'ing it properly). So I came up with this crude implementation 
> > below and it seems to be working for one or more arguments:
> > 
> > #lang typed/racket
> > 
> > (: memoize (All (r a ...)
> >                (-> (-> a ... a r)
> >                      (-> a ... a r))))
> > (define (memoize fn)
> >  (let ([store : (HashTable Any r) (make-hash)])
> >    (define (memfn . [args : a ... a])
> >      (hash-ref store args
> >                (lambda ()
> >                  (let ([result : r (apply fn args)])
> >                    (hash-set! store args result)
> >                    result))))
> >    memfn))
> > 
> > So the typical fibo function with this memoization function would look like:
> > 
> > (: fibo (-> Integer Integer))
> > (define fibo (memoize (lambda ([n : Integer])
> >                        (if (<= n 1)
> >                            1
> >                            (+ (fibo (- n 1))
> >                               (fibo (- n 2)))))))
> > 
> > However, what I wanted is to define a macro similar to define/memo like in 
> > the Racket memoize package. A first approach like below did not work:
> > 
> > (define-syntax (define-memoized stx)
> >  (syntax-parse stx
> >    [(_ (fn-name:id arg:id ...) body ...+)
> >     #'(define fn-name (memoize (lambda (arg ...) body ...)))]))
> > 
> > The error comes in (<= n 1) call where it is given Any but expecting 
> > Integer. The problem is that the syntax splits the function definition in a 
> > lambda expression and then passes to memoize function, whose result is then 
> > assigned to the function name. The lambda expression without type 
> > annotation assumes that the arguments are Any. 
> > 
> > So in this case, is there any way we could write a macro on top of the 
> > above memoize that can identify the types of the underlying function and 
> > annotate the lambda accordingly - or is there any other way this could be 
> > achieved?
> > 
> > Thanks!
> > 
> > -- 
> > You received this message because you are subscribed to the Google Groups 
> > "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send an 
> > email to [email protected].
> > For more options, visit https://groups.google.com/d/optout.

This approach seems like the easiest and flexible way to define the macro. Just 
to add, here's another crude version of the macro I came up with where we can 
specify the type declaration inside the macro, rather than outside which gives 
some way to use it in the function definition:

(define-syntax (memoized stx)
  (syntax-parse stx
    ((_ type-decl (define (fn-name:id arg:id ...+) body ...+))
     (let ([type-decl-v (syntax->datum #'type-decl)])
       (if (not (and (list? type-decl-v)
                     (eqv? (car type-decl-v) ':)))
           (error "Bad type declaration!")
           (let* ([new-fn-name (gensym)]
                  [old-fn-name (syntax->datum #'fn-name)]
                  [new-type-decl-v (map (lambda (s) (if (equal? s old-fn-name) 
new-fn-name s)) type-decl-v)])
             (with-syntax ([fn-temp-name (datum->syntax stx new-fn-name)]
                           [new-type-decl (datum->syntax stx new-type-decl-v)])
               #'(begin
                   new-type-decl
                   (define (fn-temp-name arg ...) body ...)
                   type-decl
                   (define fn-name (memoize fn-temp-name))))))))
    ((_ (define (fn-name:id arg:id ...+) body ...+))
     #'(define fn-name (memoize (lambda (arg ...) body ...))))))


And now the fibo definition becomes like this:

(memoized
 (: fibo (-> Integer Integer))
 (define (fibo n)
   (if (<= n 1)
       n
       (+ (fibo (- n 1))
          (fibo (- n 2))))))

Of course this now itroduces a temporary function with the actual definition as 
a drawback.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to