Further attempts at a map: macro which works with λget.

This commit is contained in:
Georges Dupéron 2016-01-18 22:59:28 +01:00
parent 1f2dac24ba
commit 965669da60
6 changed files with 372 additions and 97 deletions

View File

@ -18,15 +18,18 @@
(define-tagged tabc t [a 1] [b 'b] [c "c"])
|#
(require (submod "graph3.lp2.rkt" test))
(require "graph3.lp2.rkt")
(require "graph4.lp2.rkt")
(require "map.rkt")
(require "structure.lp2.rkt")
(require "variant.lp2.rkt")
(require "../lib/low.rkt")
(require "../type-expander/type-expander.lp2.rkt")
(require "__DEBUG_require.rkt")
;; (map: (compose (curry map identity) (λget houses …)) (get g streets))
;; (map: (compose (λget houses …) (λ #:∀ (A) ([x : A]) x)) (get g streets))
;; (map: (compose (λget houses …) (curry map (λget owner))) (get g streets))
;; => TODO: Crashes ../type-expander/type-expander.lp2.rkt:90:7: syntax-local-bind-syntaxes: contract violation
; expected: (listof identifier?)
; given: (#<syntax:/home/georges/phc/racket/graph-lib/graph/map.rkt:130:18 (has-get Out houses …)>)
; argument position: 1st
; other arguments...:
#|
(get '((1 2) (3)) )
(structure-get (cadr (force g)) people)
(get g people)
@ -37,6 +40,7 @@
((λget streets houses owner name) g)
(let ([f (λget streets houses owner name)]) f)
;(map: (λget houses … owner name) (get g streets))
|#
#|

View File

@ -0,0 +1,19 @@
#lang typed/racket
(require (submod "graph3.lp2.rkt" test))
(require "graph3.lp2.rkt")
(require "graph4.lp2.rkt")
(require "map.rkt")
(require "structure.lp2.rkt")
(require "variant.lp2.rkt")
(require "../lib/low.rkt")
(require "../type-expander/type-expander.lp2.rkt")
(provide (all-from-out (submod "graph3.lp2.rkt" test)
"graph3.lp2.rkt"
"graph4.lp2.rkt"
"map.rkt"
"structure.lp2.rkt"
"variant.lp2.rkt"
"../lib/low.rkt"
"../type-expander/type-expander.lp2.rkt"))

View File

@ -5,12 +5,15 @@
syntax/parse
syntax/parse/experimental/template
"../lib/low-untyped.rkt")
(for-meta 2
racket/base
racket/syntax)
"../lib/low.rkt"
"map1.rkt"
"graph4.lp2.rkt"
"../type-expander/type-expander.lp2.rkt")
(provide map:)
(provide map: apply-compose) ;; TODO: move apply-compose to lib/low.rkt
(begin-for-syntax
(define-syntax-class lam
@ -50,6 +53,7 @@
(begin-for-syntax
(define-syntax-class map-info
(pattern (_ #:in in-type
#:in-∀ [in-∀ ]
#:out out-type
#:∀ (∀-type )
#:arg-funs ([arg-fun
@ -58,12 +62,21 @@
fun-in fun-out] )
#:funs [fun ]))))
(define-for-syntax (:map* stx* stx-&ls stx-out)
(begin-for-syntax
(define-syntax (mk-info stx)
(syntax-case stx ()
[(_ . rest-stx)
(begin
(define/with-syntax whole-stx (syntax/loc stx (info . rest-stx)))
#'(syntax-parse #`whole-stx
[i:map-info #'i]))])))
(define-for-syntax (:map* stx* stx-&ls stx-out stx-out-∀)
(if (stx-null? stx*)
'()
(syntax-parse (:map (stx-car stx*) stx-&ls stx-out)
(syntax-parse (:map (stx-car stx*) stx-&ls stx-out stx-out-∀)
[info:map-info
(let ([r (:map* (stx-cdr stx*) stx-&ls #'info.in-type)]
(let ([r (:map* (stx-cdr stx*) stx-&ls #'info.in-type #'[info.in-∀ ])]
[auto (attribute info.auto-in)])
(if (and (not (null? auto)) (car auto) (not (null? r)))
(syntax-parse (car r)
@ -76,88 +89,102 @@
info.param-fun
r-info.out-type ;;info.fun-in ;;;
info.fun-out] )])
(cons #`(info #:in info.in-type
#:out info.out-type
#:∀ (info.∀-type )
#:arg-funs (#,(stx-car replaced)
#,@(stx-cdr intact))
#:funs [info.fun ])
(cons (mk-info #:in info.in-type
#:in-∀ [info.in-∀ ]
#:out info.out-type
#:∀ (info.∀-type )
#:arg-funs (#,(stx-car replaced)
#,@(stx-cdr intact))
#:funs [info.fun ])
r))])
(cons #'info r)))])))
(define-for-syntax (:map stx stx-&ls stx-out)
(define-for-syntax (:map stx stx-&ls stx-out stx-out-∀)
(define/with-syntax (&l ) stx-&ls)
(define/with-syntax out stx-out)
(define/with-syntax (out-∀ ) stx-out-∀)
(syntax-parse (remove-identities1 stx)
[(~literal car)
#'(info #:in (Pairof out Any) #:out out #:∀ ()
#:arg-funs () #:funs (car))]
#'(info #:in (Pairof out Any) #:in-∀ [] #:out out #:∀ []
#:arg-funs [] #:funs [car])]
[(~literal cdr)
#'(info #:in (Pairof Any out) #:out out #:∀ ()
#:arg-funs () #:funs (cdr))]
#'(info #:in (Pairof Any out) #:in-∀ [] #:out out #:∀ []
#:arg-funs [] #:funs [cdr])]
;; TODO: should remove `identity` completely, doing (map identity l) is
;; useless appart for constraining the type, but it's an ugly way to do so.
[(~literal identity)
#'(info #:in out #:out out #:∀ ()
#:arg-funs () #:funs (identity))]
#'(info #:in out #:in-∀ [] #:out out #:∀ []
#:arg-funs [] #:funs [identity])]
[((~literal compose) f )
(syntax-parse (:map* #'(f ) #'(&l ) #'out)
(syntax-parse (:map* #'(f ) #'(&l ) #'out #'[out-∀ ])
[(~and (_ rightmost:map-info) (leftmost:map-info . _) (:map-info ))
#'(info #:in rightmost.in-type
#:in-∀ [rightmost.in-∀ ];; ??
#:out leftmost.out-type
#:∀ (∀-type )
#:arg-funs ([arg-fun param-fun fun-in fun-out] )
#:funs (fun ))])]
#:∀ [∀-type ]
#:arg-funs [(arg-fun param-fun fun-in fun-out) ]
#:funs [fun ])])]
[((~literal curry) :mapp f)
(syntax-parse (internal-map: #'f #'(&l ) #'out)
(syntax-parse (internal-map: #'f #'(&l ) #'out #'[out-∀ ])
[(i:map-info . code)
#'(info #:in (Listof i.in-type)
#`(info #:in (Listof i.in-type)
#:in-∀ [i.in-∀ ];; ??
#:out (Listof out)
#:∀ [i.∀-type ]; i.out-type
#:arg-funs [(i.arg-fun i.param-fun i.fun-in i.fun-out) ]
#:funs [(code i.fun _)])])]
#:funs [#,(syntax/loc #'f (code i.fun _))])])]
[(~literal length)
(define-temp-ids "&~a" f)
(define-temp-ids "~a/in" f)
#'(info #:in f/in #:out out #:∀ (f/in)
#:arg-funs ([(λ ([l : (Listof Any)]) (length l))
#'(info #:in f/in #:in-∀ [f/in] #:out out #:∀ [f/in] ;;??
#:arg-funs [((λ ([l : (Listof Any)]) (length l))
&f
#:auto-in f/in
out])
#:funs (&f))]
out)]
#:funs [&f])]
[((~literal λget) pat )
#'(info #:in (has-get out pat )
#:in-∀ [out-∀ ]
#:out (result-get out pat )
#:∀ []
#:arg-funs []
#:funs [(get _ pat )])]
[f
(define-temp-ids "&~a" f)
(define-temp-ids "~a/in" f)
#'(info #:in f/in #:out out #:∀ (f/in)
#:arg-funs ([f &f #:auto-in f/in out]) #:funs (&f))]))
#'(info #:in f/in #:in-∀ [f/in] #:out out #:∀ [f/in] ;;??
#:arg-funs [(f &f #:auto-in f/in out)] #:funs [&f])]))
(define-syntax (apply-compose stx)
(syntax-parse stx
[(_ [] [a ])
#'(values a )]
[(_ [f (f-last x (~literal _) y )] [a ])
#'(apply-compose [f ] [(f-last x a y )])]
[(_ [f (~and loc (f-last x (~literal _) y ))] [a ])
#`(apply-compose [f ] [#,(syntax/loc #'loc (f-last x a y ))])]
[(_ [f f-last] [a ])
#'(apply-compose [f ] [(f-last a )])]))
#`(apply-compose [f ] [#,(syntax/loc #'f-last (f-last a ))])]))
(define-for-syntax (internal-map: stx-f stx-&ls stx-out)
(define-for-syntax (internal-map: stx-f stx-&ls stx-out stx-out-∀)
(define/with-syntax f stx-f)
(define/with-syntax (&l ) stx-&ls)
(define/with-syntax out stx-out)
(syntax-parse (:map #'f #'(&l ) #'out)
(define/with-syntax (out-∀ ) stx-out-∀)
(syntax-parse (:map #'f #'(&l ) #'out #'[out-∀ ])
[(~and i :map-info)
(define/with-syntax map1 (generate-temporary #'map))
(cons #'i
#'(let ()
(: map1 ( [out ∀-type ]
( ( fun-in fun-out)
(Listof in-type)
(Listof out-type))))
(define (map1 param-fun &l )
(if (or (null? &l) )
'()
(cons (apply-compose [fun ] [(car &l) ])
(map1 param-fun (cdr &l) ))))
map1))]));(map1 arg-fun … . ls)
(template
(let ()
(: map1 ( [out-∀ ∀-type ]
( ( fun-in fun-out)
(Listof in-type)
(Listof out-type))))
(define (map1 param-fun &l )
(if (or (null? &l) )
'()
(cons (apply-compose [fun ] [(car &l) ])
(map1 param-fun (cdr &l) ))))
map1)))]));(map1 arg-fun … . ls)
;; TODO: inefficient at compile-time: we run (:map #'f #'Out) twice.
;; Plus it could cause some bugs because of differing #'Out.
@ -165,7 +192,7 @@
(syntax-parse stx
[(_ (~optional (~and norun (~literal norun))) f l )
(define-temp-ids "&~a" (l ))
(syntax-parse (internal-map: #'f #'(&l ) #'Out)
(syntax-parse (internal-map: #'f #'(&l ) #'Out #'[Out])
[(:map-info . code)
(if (attribute norun)
#'(ann '(code arg-fun l ) Any)
@ -239,54 +266,54 @@
;; the map: identifier with a contract, so the identifier seen outside the
;; module is not the same as the one used in the syntax-parse ~literal clause.
#;(begin
(check-equal?: (map: (curry map add1) '((1 2 3) (4 5)))
: (Listof (Listof Number))
'((2 3 4) (5 6)))
#;(check-equal?: (map: (curry map: add1) '((1 2 3) (4 5)))
#|(begin
(check-equal?: (map: (curry map add1) '((1 2 3) (4 5)))
: (Listof (Listof Number))
'((2 3 4) (5 6)))
(check-equal?: (map: (curry map (compose number->string add1))
'((1 2 3) (4 5)))
: (Listof (Listof String))
'(("2" "3" "4") ("5" "6")))
#;(check-equal?: (map: (curry map: (compose number->string add1))
#;(check-equal?: (map: (curry map: add1) '((1 2 3) (4 5)))
: (Listof (Listof Number))
'((2 3 4) (5 6)))
(check-equal?: (map: (curry map (compose number->string add1))
'((1 2 3) (4 5)))
: (Listof (Listof String))
'(("2" "3" "4") ("5" "6")))
(check-equal?: (map: add1 '(1 2 3))
: (Listof Number)
'(2 3 4))
(check-equal?: (map: car '((1 a) (2 b) (3 c)))
: (Listof Number)
'(1 2 3))
(check-equal?: (map: (curry map car) '([(1 a) (2 b)] [(3 c)]))
: (Listof Number)
'((1 a) (3 c)))
#;(check-equal?: (map: (curry map: car) '([(1 a) (2 b)] [(3 c)]))
#;(check-equal?: (map: (curry map: (compose number->string add1))
'((1 2 3) (4 5)))
: (Listof (Listof String))
'(("2" "3" "4") ("5" "6")))
(check-equal?: (map: add1 '(1 2 3))
: (Listof Number)
'(2 3 4))
(check-equal?: (map: car '((1 a) (2 b) (3 c)))
: (Listof Number)
'(1 2 3))
(check-equal?: (map: (curry map car) '([(1 a) (2 b)] [(3 c)]))
: (Listof Number)
'((1 a) (3 c)))
(check-equal?: (map: (curry map (curry map car))
'([((1 a) (2 b)) ((3 c))] [((4))]))
: (Listof (Listof (Listof Number)))
'([(1 2) (3)] [(4)]))
#;(check-equal?: (map: (curry map (curry map: car))
#;(check-equal?: (map: (curry map: car) '([(1 a) (2 b)] [(3 c)]))
: (Listof Number)
'((1 a) (3 c)))
(check-equal?: (map: (curry map (curry map car))
'([((1 a) (2 b)) ((3 c))] [((4))]))
: (Listof (Listof (Listof Number)))
'([(1 2) (3)] [(4)]))
#;(check-equal?: (map: (curry map: (curry map car))
'([((1 a) (2 b)) ((3 c))] [((4))]))
: (Listof (Listof (Listof Number)))
'([(1 2) (3)] [(4)]))
#;(check-equal?: (map: (curry map: (curry map: car))
'([((1 a) (2 b)) ((3 c))] [((4))]))
: (Listof (Listof (Listof Number)))
'([(1 2) (3)] [(4)])))
#;(check-equal?: (map: (curry map (curry map: car))
'([((1 a) (2 b)) ((3 c))] [((4))]))
: (Listof (Listof (Listof Number)))
'([(1 2) (3)] [(4)]))
#;(check-equal?: (map: (curry map: (curry map car))
'([((1 a) (2 b)) ((3 c))] [((4))]))
: (Listof (Listof (Listof Number)))
'([(1 2) (3)] [(4)]))
#;(check-equal?: (map: (curry map: (curry map: car))
'([((1 a) (2 b)) ((3 c))] [((4))]))
: (Listof (Listof (Listof Number)))
'([(1 2) (3)] [(4)])))|#
(check-equal?: (map: car '((1 b x) (2 c) (3 d)))
: (Listof Number)
@ -427,3 +454,5 @@ EDIT: that's what we did, using the #:auto-in
|#
;|#

150
graph-lib/graph/map3.rkt Normal file
View File

@ -0,0 +1,150 @@
#lang typed/racket
(require (for-syntax racket/syntax
syntax/stx
syntax/parse
syntax/parse/experimental/template
"../lib/low-untyped.rkt")
"../lib/low.rkt"
"graph4.lp2.rkt"
"../type-expander/type-expander.lp2.rkt")
;; TODO: DEBUG
(define-syntax (dbg stx)
(syntax-parse stx
[(_ (~optional (~and norun #:norun)) code)
(if (attribute norun)
#'(ann 'code Any)
#'code)]))
(begin-for-syntax
(define-template-metafunction (apply-compose stx)
(syntax-parse stx
[(_ [] [a])
#'a]
[(_ [] [a ])
#'(values a )]
[(_ [f (~and loc (f-last x (~literal _) y ))] [a ])
(quasitemplate
(apply-compose [f ] [#,(syntax/loc #'loc (f-last x a y ))]))]
[(_ [f f-last] [a ])
(quasitemplate
(apply-compose [f ] [#,(syntax/loc #'f-last (f-last a ))]))])))
(begin-for-syntax
(define-syntax-class fun-descriptor
(pattern [in:expr f-auto:expr out:expr]
#:with code (generate-temporary #'f-auto)
#:with (f-arg ) #'(f-auto)
#:with (f-param ) #'(code)
#:with (f-type ) #'[( in out)])
(pattern [in:expr
{[f-arg:expr f-param:id f-type:expr] }
code:expr
out:expr])))
(define-syntax (map0 stx)
(syntax-parse stx
[(_ (~optional (~and norun #:norun))
#:∀ {∀-T:id } global-out:expr
:fun-descriptor )
(define/with-syntax local-map (generate-temporary 'map))
(define/with-syntax lst (generate-temporary 'lst))
(define/with-syntax (_ inner-in) #'(in ))
(define/with-syntax icons #'(inst cons global-out (Listof global-out)))
(quasitemplate
(dbg (?? norun)
(let ()
(: local-map ( (∀-T ) ( f-type
(Listof inner-in)
(Listof global-out))))
(define (local-map f-param lst)
(if (null? lst)
'()
(icons (apply-compose [code ] [(car lst)])
(local-map f-param (cdr lst)))))
local-map)))]))
(define-syntax (call-map0 stx)
(syntax-parse stx
[(_ (~optional (~and norun #:norun))
l:expr #:∀ {∀-T:id } global-out:expr d:fun-descriptor )
(quasitemplate
(dbg (?? norun)
#,(syntax/loc stx
((map0 #:∀ {∀-T } global-out d ) d.f-arg l))))]))
(call-map0 #:norun '((a 1) (b 2) (c 3))
#:∀ {O}
O
[(Pairof O Any) car O]
[(Pairof Any (Pairof O Any)) cdr (Pairof O Any)])
(call-map0 #:norun '(1 2 3)
#:∀ {A B}
B
[A add1 B]
[A identity A])
(call-map0 #:norun '(1 2 3)
#:∀ {A B}
B
[A add1 B]
[A identity A])
(call-map0 '((1 2) (3)) #:∀ {A B}
(Listof B)
[(Listof A) {[add1 add1*1 ( A B)]}
(call-map0 _ #:∀ {A B} B [A add1*1 B])
(Listof B)])
(call-map0 '((1 2) (3)) #:∀ {A B C}
(Listof C)
[(Listof B) {[add1 add1*2 ( B C)]}
(call-map0 _ #:∀ {B C} C [B add1*2 C])
(Listof C)]
[(Listof A) {[add1 add1*1 ( A B)]}
(call-map0 _ #:∀ {A B} B [A add1*1 B])
(Listof B)])
(call-map0 '((1 2) (3)) #:∀ {A Y B X C}
(Listof C)
[(Listof B) {[add1 add1*2 ( B X)]
[add1 add1*2b ( X C)]}
(call-map0 _ #:∀ {B X C} C
[X add1*2b C]
[B add1*2 X])
(Listof C)]
[(Listof A) {[add1 add1*1 ( A Y)]
[add1 add1*1b ( Y B)]}
(call-map0 _ #:∀ {A Y B} B
[Y add1*1b B]
[A add1*1 Y])
(Listof B)])
(call-map0 '(([1 b] [2 c]) ([3 d])) #:∀ {A X C}
(Listof C)
[(Listof A) {[add1 add1*2 ( A X)]
[add1 add1*2b ( X C)]}
(call-map0 _ #:∀ {A X C} C
[X add1*2b C]
[A add1*2 X])
(Listof C)]
[(Listof (Pairof A Any)) {}
(call-map0 _ #:∀ {A} A
[(Pairof A Any) car A])
(Listof A)])
#;(call-map0 '(([1 b] [2 c]) ([3 d])) #:∀ {A X C}
(Listof C)
[(Listof (Pairof A Any))
{[add1 add1*2b ( A C)]}
(call-map0 _ #:∀ {A C} C
[A add1*2b C]
[(Pairof A Any) car A])
(Listof C)]
[(Listof (Pairof (Pairof A) Any))
{}
(call-map0 _ #:∀ {A} A
[(Pairof (Pairof A Any) Any) car A])
(Listof (Pairof A Any))])

72
graph-lib/graph/map4.rkt Normal file
View File

@ -0,0 +1,72 @@
#lang typed/racket
(require (for-syntax racket/syntax
syntax/stx
syntax/parse
syntax/parse/experimental/template
"../lib/low-untyped.rkt")
"../lib/low.rkt"
"graph4.lp2.rkt"
"../type-expander/type-expander.lp2.rkt")
(begin-for-syntax
(define-syntax-class >0
(pattern v #:when (exact-positive-integer? (syntax-e #'v)))))
(begin-for-syntax
(define-syntax-class ≥0
(pattern v #:when (exact-integer? (syntax-e #'v)))))
(define-type-expander (Deep-Listof stx)
(syntax-parse stx
[(_ 0 T)
#'T]
[(_ d:>0 T)
#`(Listof (Deep-Listof #,(sub1 (syntax-e #'d)) T))]))
(define-syntax (λdeep-map stx)
(syntax-parse stx
[(_ {∀-type:id } A:expr B:expr 0)
#'(ann (λ (f x) (f x))
( (∀-type ) ( ( A B) A B)))]
[(_ {∀-type:id } A:expr B:expr d:exact-integer)
(define/with-syntax local-map (generate-temporary #'map))
#`(let ()
(: local-map ( (∀-type ) ( ( A B)
(Deep-Listof d A)
(Deep-Listof d B))))
(define (local-map f l)
(if (null? l)
'()
(cons ((λdeep-map {∀-type } A B #,(sub1 (syntax-e #'d)))
f (car l))
(local-map f (cdr l)))))
local-map)]))
(module+ test
(check-equal?: ((λdeep-map {A B} A B 3) add1 '([{1} {2 3}] [{4}]))
: (Listof (Listof (Listof Number)))
'([{2} {3 4}] [{5}])))
#|
(define-syntax (deep-map stx)
(syntax-parse stx
[(_ d:≥0 f:expr l:expr)
(syntax/loc #'f ((λdeep-map d) f l))]))
(deep-map 3 add1 '([{1} {2 3}] [{4}]))
;; Now we turn all map: calls into the form
;; (compose-maps [(d f) …] [l …])
(define-syntax (compose-maps stx)
(syntax-parse stx
[(_ [] [l])
#'l]
[(_ [] [l:expr ])
#'(values l )]
[(_ [(d:≥0 f:expr) (d-rest:≥0 f-rest:expr) ] [l:expr ])
#'(deep-map d f (compose-maps [(d-rest f-rest) ] [l ]))]))
(compose-maps [(3 add1) (3 add1)] ['([{1} {2 3}] [{4}])])
|#

View File

@ -91,7 +91,8 @@ else.
(let ([def-ctx (syntax-local-make-definition-context)]
[err-expr #'(λ _ (raise-syntax-error
"Type name used out of context"))])
(for ([var (syntax->list type-vars)])
(for ([var (syntax-parse type-vars
[(v:id ) (syntax->list #'(v ))])])
(syntax-local-bind-syntaxes (list var) err-expr def-ctx))
(internal-definition-context-seal def-ctx)
(internal-definition-context-introduce def-ctx stx)))]
@ -121,9 +122,9 @@ else.
[(((~literal curry) T Arg1 ) . Args2)
(expand-type #'(T Arg1 . Args2))]
;; TODO: handle the pattern (∀ (TVar ... ooo) T)
[(∀:fa (TVar ...) T)
[(∀:fa (TVar:id ...) T:expr)
#`( (TVar ...) #,(expand-type (bind-type-vars #'(TVar ...) #'T)))]
[((~literal Rec) R T)
[((~literal Rec) R:id T:expr)
#`(Rec R #,(expand-type (bind-type-vars #'(R) #'T)))]
[((~literal quote) T) (expand-quasiquote 'quote 1 #'T)]
[((~literal quasiquote) T) (expand-quasiquote 'quasiquote 1 #'T)]
@ -309,7 +310,7 @@ variables in the result, we define two template metafunctions:
(define-template-metafunction (tmpl-expand-type stx)
(syntax-parse stx
[(_ () t) (expand-type #'t)]
[(_ tvars t) (expand-type (bind-type-vars #'tvars #'t))]))]
[(_ (tvar ) t) (expand-type (bind-type-vars #'(tvar ) #'t))]))]
@subsection{@racket[:]}