3

我的问题是参考这篇文章,特别是:

data Actions a = Actions {
    actEval :: a,
    actMap  :: (a -> a) -> Actions a }

我对actMap函数的递归定义感到困惑,因为它递归地返回对 的引用Actions,即递归的基本情况是什么,因为没有为 指定类型a

ActionsCommon Lisp 中如何表示结构?

编辑:另外,Actions构造函数需要 2 个参数(如原帖中所述)。那么Actions a返回的? 是什么actMap

4

3 回答 3

1

首先不要将类型构造函数与数据构造函数混淆。

data Actions a = ..

Actions是一个类型构造函数。它接受一个类型a并给出一个类型Actions a,而

data Actions a = Actions ..

第二个Actions是数据构造函数。因此,要构造一个类型的值,Actions a您需要使用Actions具有两个值的数据构造函数,一个是 type a,另一个是 type (a -> a) -> Actions a

的定义Actions在类型方面是递归的,这并不意味着您需要有一个基本案例。您可以将上述类型的值构造为

construct :: a -> Actions a
construct v = Actions v (\fn -> construct $ fn v)

这是一个有效的构造,因为数据构造函数的第一个值是类型a,另一个是上述指定类型的函数。

于 2012-12-13T19:53:44.223 回答
0

正如@Satvik 提到的,不要将数据类型与其构造函数混淆。定义可以改为

data Actions a = ActionsConstructor {
    actEval :: a,
    actMap  :: (a -> a) -> Actions a }

这更好地区分了这两个概念。

这是一种标准的递归数据类型。这与列表非常相似,例如:

data List a = Nil | Cons { head :: a, tail :: List a }

只有在 的情况下Actions,结构可能是无限的——你总是可以传递另一个函数来actMap获得另一个动作,而一个列表可以Nil在某个地方终止。

于 2012-12-14T08:50:49.323 回答
0

好吧,在 Lisp 中,它可以表示为一个结构:

(defstruct act eval map)

为了跟进提到的帖子,您可以像这样使用它:

(defun mk-lit (x)
  (make-act :eval x
            :map (lambda (f) (mk-lit (funcall f x)))))

(defun mk-sum (x y)
  (make-act :eval (+ (act-eval x) (act-eval y))
            :map (lambda (f)
                   (mk-sum (funcall (act-map x) f)
                           (funcall (act-map y) f)))))

CL-USER> (mk-sum (mk-lit 1) (mk-lit 2))
#S(ACT :EVAL 3 :MAP #<CLOSURE (LAMBDA # :IN MK-SUM) {100471902B}>)

CL-USER> (funcall (act-map (mk-sum (mk-lit 1) (mk-lit 2)))
                  #'print)
1 
2 
#S(ACT :EVAL 3 :MAP #<CLOSURE (LAMBDA # :IN MK-SUM) {1007E476FB}>)

编辑:但这绝对不是在 Lisp 中处理此类问题的最佳方法 - 有更简单和强大的方法。

于 2012-12-14T06:08:04.027 回答