如何在Haskell中表示加糖的λ项?

时间:2016-05-03 21:02:38

标签: haskell racket lambda-calculus

使用此语法设置含糖λ演算的数据定义。

Λ → v
Λ → ( λ v Λ )
Λ → ( Λ Λ )
Λ → (L Λ)
L → (LET (LL) Λ)
LL → (v Λ)

这是他们希望我做的。所以我为DrRacket做了这个。我怎么能为Haskell做这个?

这是我在DrRacket中的代码:

;; λ-expression grammar
;; λ-calc -> v
;; λ-calc -> (λ-calc λ-calc)
;; λ-calc -> (λ v λ-calc)

(define-type λ-calc
  (λ-sym (v : symbol))
  (λ-app (l : λ-calc)(r : λ-calc))
  (λ-def (v : symbol)(expr : λ-calc))
  )


;; Tests;;
(λ-sym 'x)
(λ-app (λ-sym 'x)(λ-sym 'y))
(λ-def 'v (λ-app (λ-sym 'x)(λ-sym 'y)))


;; parse : s-expression -> λ
;; Examples
;; 'x -> (λ-sym 'x)
;; '(x y) -> (λ-app (λ-sym 'x) (λ-sym 'y))
;; '(λ x y) -> (λ-def 'x (λ-sym 'y))
;; '((λ x y) (x y)) -> (λ-app (λ-def 'x (λ-sym 'y)) (λ-app (λ-sym 'x) (λ-sym 'y)))
;; Template
;; (define (parse [expr : s-expression]) : λ
;;   (cond
;;     [(s-exp-symbol? expr) (λ-var (... expr))]
;;     [(s-exp-list? expr)
;;      (let ([sl (...expr)])
;;        (cond
;;          [(> (length sl) 2)  (... ) (parse ...))]
;;          [else  (parse ...)) (parse ...)))])
;;        )]
;;     [else (error 'parse ...)]))


(define (parse (ex : s-expression)) : λ-calc
  (cond
    [(s-exp-symbol? ex)(λ-sym (s-exp->symbol ex))]
    [(s-exp-list? ex)
     (let ([ex-list (s-exp->list ex)])
       (cond
         [(= 2 (length ex-list)) (λ-app (parse (first ex-list))(parse (second ex-list)))]
         [(= 3 (length ex-list)) (if (and (symbol=? 'λ (s-exp->symbol (first ex-list))) (s-exp-symbol? (second ex-list)))
                                 (λ-def (s-exp->symbol(second ex-list))
                                 (parse (third ex-list)))
              (error 'parse "Wrong lambda calc")
              )]
         [else (error 'parse "List length is unexpectedly big")]
         ))]
    [else (error 'parse "This is not lambda")]
    ))

;; Examples
;; (λ-sym 'x) -> 'x
;; (λ-app (λ-def 'x) (λ-sym 'y)) -> '(x y)
;; Template
;;(define (unparse (le : λ-calc)) : s-expression
;;  (type-case λ-calc le
;;    (λ-sym (v) (v)) 
;;    (λ-app (l r)(... (unparse l)(unparse r))))
;;    (λ-def (v expr)(...
;;                   v)(unparse expr))))

(define (unparse (le : λ-calc)) : s-expression
  (type-case λ-calc le
    (λ-sym (v) (symbol->s-exp v)) 
    (λ-app (l r)(list->s-exp (list (unparse l)(unparse r))))
    (λ-def (v expr)(list->s-exp 
                 (list (symbol->s-exp 'λ)(symbol->s-exp v)(unparse expr))))
    ))


;;  λ-calc  symbol  λ-calc -> λ-calc
;;Template
;;(define (substituter [what : λ-calc] [for : symbol] [in : λ-calc]) : λ-calc 
;;  (type-case λ-calc in
;;    (λ-sym (v) (if (symbol=? ...) 
;;                 what
;;                   in))
;;  (λ-app (l r) (λ-app (....) (.....)))
;;    (λ-def (v expr)(λ-def v (substituter what for expr))))

(define (substituter [what : λ-calc] [for : symbol] [in : λ-calc]) : λ-calc 
  (type-case λ-calc in
    (λ-sym (v) (if (symbol=? v for) 
                   what
                   in))
    (λ-app (l r) (λ-app (substituter what for l)
                        (substituter what for r)))
    (λ-def (v expr)(λ-def v (substituter what for expr)))
    )
  )


;; beta-transformer : ((λ x M) N) --> [M:x=N]
;;;; (λx x) y -> (y)
;; ( ((λx x) (λy y)) ((λx x) (y y)) ) -> ( (λy y) ((λx x) (y y)) )
;; Template
;;(define (beta-transformer (le : λ-calc)) : λ-calc;;
;;(type-case λ-calc le
;;    (λ-sym (v) ) 
;;    (λ-app (l r) (if (λ-def? l) (...))
;;                     (λ-app (beta-transformer l) (beta-transformer r))))
;;    (λ-def (v expr) (λ-def ....)))))

(define (beta-transformer (le : λ-calc)) : λ-calc
  (type-case λ-calc le
    (λ-sym (v) le) 
    (λ-app (l r) (if (λ-def? l)
                     (substituter r (λ-def-v l) (λ-def-expr l))
                     (λ-app (beta-transformer l) (beta-transformer r))))
    (λ-def (v expr) (λ-def v (beta-transformer expr)))))





;; A set represented as a list.
;; union : (listof symbol) (listof symbol) -> (listof symbol)
;; finding the union of two sets.
(define (union (s1 : (listof symbol)) (s2 : (listof symbol))) : (listof symbol)
  (foldr (lambda (x y)
           (if (member x y)
               y
               (cons x y))) 
         empty
         (append s1 s2)))


;; set-difference : (listof symbol) (listof symbol) -> (listof symbol)
;; To find the set difference of two sets.
(define (set-difference (s1 : (listof symbol))  (s2 : (listof symbol))) : (listof symbol)
  (filter (lambda (x)
            (not (member x s2)))
          s1))

;; Tests:
(test (union empty empty) empty)
(test (union empty (list 'x)) (list 'x))
(test (union (list 'x)(list 'x 'y)) (list 'x 'y))

(test (parse (symbol->s-exp 'y))(λ-sym 'y))
(test (parse '(λ x x))(λ-def 'x (λ-sym 'x)))
(test (parse '((λ x x) y))(λ-app (λ-def 'x (λ-sym 'x)) (λ-sym 'y)))

(test (unparse (λ-sym 'y))(symbol->s-exp 'y))
(test (unparse (λ-def 'x (λ-sym 'x))) '(λ x x))
(test (unparse (λ-app (λ-def 'x (λ-sym 'x)) (λ-sym 'y)))
      '((λ x x) y))

(test (beta-transformer (parse '((λ x x) a)))
      (parse (symbol->s-exp 'a)))

(test (beta-transformer (parse '((λ x y) a)))
      (parse (symbol->s-exp 'y)))

(test (beta-transformer (parse '((λ x (a b)) k)))
      (parse '(a b)))

(test (beta-transformer (parse '((λ x (λ x y)) k)))
      (parse '(λ x y)))

(test (beta-transformer (parse '((λ x (λ y x)) k)))
      (parse '(λ y k)))

(test (beta-transformer (parse '((λ x (λ y (x y))) k)))
      (parse '(λ y (k y))))



    ;; Redex, lambda calculus leftmost inner form
    ;; Template
    ;; (define (leftReduction x) : s-exp
    ;;  (type-case λ-calc 
    ;;    [λ-sym (v) (v)]
    ;;    [λ-def (v expr) (unparse)]
    ;;    [λ-app (l r) (unparse )]))
    ;;(test (leftReduction (λ-def (λ-sym 'a) (λ-(λ-def 'x (λ-sym 'x))) '(λ x x)) 'b) )
    ;(test (leftReduction (λ-sym  '3)) '3)

    (define (leftReduction la) : s-expression
      (type-case λ-calc la
        [λ-sym (v) (symbol->s-exp v)]
        [λ-def (v expr) (unparse la)]
        [λ-app (l r) (unparse l)]))

1 个答案:

答案 0 :(得分:3)

这很长,所以我就开始吧。另外,我非常确定Haskell中的lambda解释器已经写在了网络的某个地方。

(define-type λ-calc
  (λ-sym (v : symbol))
  (λ-app (l : λ-calc)(r : λ-calc))
  (λ-def (v : symbol)(expr : λ-calc))
  )

在Haskell中,您可以定义相应的代数数据类型

type Symbol = String
data Lcalc
   = Lsym Symbol
   | Lapp Lcalc Lcalc
   | Ldef Symbol Lcalc
   deriving (Show)  -- and possibly Eq, Ord

对于测试

;; Tests;;
(λ-sym 'x)
(λ-app (λ-sym 'x)(λ-sym 'y))
(λ-def 'v (λ-app (λ-sym 'x)(λ-sym 'y)))

我们可以使用

test1, test2, test3 :: Lcalc
test1 = Lsym "x"
test2 = Lapp (Lsym "x") (Lsym "y")
test3 = Ldef "v" (Lapp (Lsym "x") (Lsym "y"))

要操纵lambda术语,需要模式匹配。 E.g。

-- free variables
free :: Lcalc -> [Symbol]
free (Lsym x) = [x]
free (Lapp s t) = nub (free s ++ free t)   -- we remove duplicates here
free (Ldef x t) = delete x (free t)