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 <soura.ja...@gmail.com> 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 racket-users+unsubscr...@googlegroups.com.
> > 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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to