PasteRack.org
Paste # 48973
2016-12-09 13:42:06

Fork as a new paste.

Paste viewed 47 times.


Embed:

  1. #lang racket
  2.  
  3. (require (for-syntax racket/set))
  4. (require (for-syntax racket/syntax))
  5. (require syntax/parse/define (for-syntax syntax/parse))
  6.  
  7. ;; ;; anything prefixed with "--" is provided out, without the prefix.
  8. ;; (require racket/provide) ;; for filtered-out, matching-identifiers-out
  9. ;; (provide
  10. ;;  (filtered-out (lambda (name) (substring name 2))
  11. ;;                (matching-identifiers-out #rx"^--" (all-defined-out))))
  12.  
  13. ;; TODO: #%top-interaction, and possibly #%top?
  14. (provide #%top-interaction)
  15.  
  16. ;; utility
  17. (define-simple-macro (let*/set (for-clause ...) body ...)
  18.   (for/set (for-clause ... [x (begin body ...)]) x))
  19.  
  20. ;; Our grammar
  21.  
  22. ;; TOP ::= DECLARE | CLAUSE
  23. ;; DECLARE ::= (pred:NAME : arg:NAME ...)
  24. ;; CLAUSE ::= (head:POSITIVE-TERM :- body:TERM ...)
  25. ;;
  26. ;; TERM ::= POSITIVE-TERM | (not POSITIVE-TERM)
  27. ;; POSITIVE-TERM ::= (pred:NAME arg:ARG ...)
  28. ;;
  29. ;; ARG ::= var:VAR | atom:NAME
  30. ;;
  31. ;; VAR = upper-case identifier
  32. ;; NAME = lower-case identifier
  33. (begin-for-syntax
  34.   (define (first-char pred id)
  35.     (define s (symbol->string (syntax->datum id)))
  36.     (and (< 0 (string-length s)) (pred (string-ref s 0))))
  37.  
  38.   (define (name? id) (first-char char-lower-case? id))
  39.   (define (var? id) (first-char char-upper-case? id))
  40.  
  41.   (define-syntax-class declare
  42.     #:datum-literals (:)
  43.     (pattern (pred:name : arg:name ...)))
  44.   (define-syntax-class clause
  45.     #:datum-literals (:-)
  46.     (pattern (head:positive-term :- body:term ...)
  47.              #:attr pred #'head.pred
  48.              #:attr (arg 1) (syntax->list #'(head.arg ...))
  49.              #:attr (all-preds 1) (syntax->list #'(pred body.pred ...))))
  50.  
  51.   (define-syntax-class term
  52.     #:datum-literals (not)
  53.     (pattern t:positive-term
  54.              #:attr pred #'t.pred
  55.              #:attr (arg 1) (syntax->list #'(t.arg ...)))
  56.     (pattern (not t:positive-term)
  57.              #:attr pred #'t.pred
  58.              #:attr (arg 1) (syntax->list #'(t.arg ...))))
  59.  
  60.   (define-syntax-class positive-term (pattern (pred:name arg:arg ...)))
  61.   (define-syntax-class arg (pattern var) (pattern name))
  62.   ;; if this is named "var" instead, and all uses are updated, the code does not
  63.   ;; compile!
  64.   (define-syntax-class var (pattern var:id #:when (var? #'var)))
  65.   (define-syntax-class name (pattern name:id #:when (name? #'name))))
  66.  
  67.  
  68. ;; The syntax transformers
  69. (provide (rename-out [datalog-module-begin #%module-begin]) )
  70. (define-syntax-parser datalog-module-begin
  71.   [(_ (~or clause:clause) ...)
  72.    ;; Extract the predicate names.
  73.    (define id-list (compose set->list list->set syntax->datum))
  74.    (define defined-preds (id-list #'(clause.pred ...)))
  75.    (define preds (id-list #'(clause.all-preds ... ...)))
  76.  
  77.    ;; (define used-preds
  78.    ;;   (syntax->list #'(clause.body)))
  79.  
  80.    ;; TODO Check arity: Declarations, definitions, and uses of a given predicate
  81.    ;; all have the same arity.
  82.  
  83.    ;; TODO Check stratification: no mutual definition cycles that go through a
  84.    ;; negation
  85.  
  86.    ;; TODO Check generativity: every variable in the head of a clause occurs in
  87.    ;; a positive position in its body.
  88.  
  89.    (define/with-syntax (pred ...) preds)
  90.    #`(#%module-begin
  91.       (displayln "hello world")
  92.       (printf "- pred: ~a\n" 'pred) ...
  93.  
  94.       ;; initialize predicate sets.
  95.       (define pred (mutable-set)) ...
  96.  
  97.       ;; the fixed-point loop
  98.       (let loop ()
  99.         (define changed #f)
  100.         (run-clause changed clause) ...
  101.         (when changed (loop))))])
  102.  
  103. (define-syntax-parser run-clause
  104.   #:datum-literals (:- not)
  105.   [(_ changed:id ((pred:name arg:arg ...)
  106.                   :-
  107.                   (~or pos-term:positive-term
  108.                        ;; (not neg-term:positive-term)
  109.                        ) ...))
  110.    #`(begin
  111.        ;; compute the set of things to add to `pred'
  112.        (define tuples (solving (pos-term ...) (list arg ...)))
  113.        (unless changed
  114.          ;; check whether we added any new elements.
  115.          (set! changed (not (subset? tuples pred))))
  116.        (set-union! pred tuples))])
  117.  
  118. ;; (solving (terms ...) body ...)
  119. (define-syntax-parser solving
  120.   [(_ (term ...) body ...)
  121.    (define-values (_ result)
  122.     (for/fold ([bound-vars (set)]
  123.                [body #'(begin body ...)])
  124.               ([term (syntax->list #'(term ...))])
  125.       (define/syntax-parse (pred:name arg:arg ...) term)
  126.       (define/syntax-parse ((~or var:var (~not _:var)) ...) #'(arg ...))
  127.       (define new-vars (list->set (syntax->datum #'(var ...))))
  128.       (define tuple-patterns
  129.         (for/list ([arg (syntax->list #'(arg ...))])
  130.           (syntax-parse arg
  131.             [atom:name #''atom]
  132.             [v:var (if (set-member? (syntax->datum #'v) bound-vars)
  133.                        #'(== v)
  134.                        #'v)]
  135.             )))
  136.       (values
  137.        (set-union bound-vars new-vars)
  138.        #`(let*/set ([tuple pred])
  139.                    (match tuple
  140.                      [(list #,@tuple-patterns) #,body]
  141.                      [_ (set)])))))
  142.    result])

=>