Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 什么';非正则递归类型的反同构(fold)的类型是什么?_Haskell_Types_Catamorphism_Recursion Schemes - Fatal编程技术网

Haskell 什么';非正则递归类型的反同构(fold)的类型是什么?

Haskell 什么';非正则递归类型的反同构(fold)的类型是什么?,haskell,types,catamorphism,recursion-schemes,Haskell,Types,Catamorphism,Recursion Schemes,许多变形似乎足够简单,主要是用自定义函数替换每个数据构造函数,例如 data Bool = False | True foldBool :: r -- False constructor -> r -- True constructor -> Bool -> r data Maybe a = Nothing | Just a foldMaybe :: b -- No

许多变形似乎足够简单,主要是用自定义函数替换每个数据构造函数,例如

data Bool = False | True
foldBool :: r              -- False constructor
         -> r              -- True constructor
         -> Bool -> r

data Maybe a = Nothing | Just a
foldMaybe :: b             -- Nothing constructor
          -> (a -> b)      -- Just constructor
          -> Maybe a -> b

data List a = Empty | Cons a (List a)
foldList :: b              -- Empty constructor
         -> (a -> b -> b)  -- Cons constructor
         -> List a -> b
但是,我不清楚的是,如果使用相同的类型构造函数,但使用不同的类型参数,会发生什么情况。例如,与其将
列表a
传递给
Cons
,不如

data List a = Empty | Cons a (List (a,a))
或者,也许是一个更疯狂的案例:

data List a = Empty | Cons a (List (List a))
foldList :: b              -- Empty constructor
         -> ???            -- Cons constructor
         -> List a -> b
对于
部分,我有两个合理的想法:

  • (a->b->b)
    ,即递归地替换
    列表
    构造函数的所有应用程序)
  • (a->List b->b)
    ,即仅替换所有
    List a
    应用程序

哪一个是正确的?为什么?还是完全不同?

这只是一个部分答案

OP提出的问题是:在非正则递归类型的情况下,如何定义
fold
/
cata

因为我不相信自己能做到这一点,所以我会求助于问Coq。让我们从一个简单、常规的递归列表类型开始

Inductive List (A : Type) : Type :=
  | Empty: List A
  | Cons : A -> List A -> List A
.
这里没什么特别的,
列表A
是根据
列表A
定义的。 (记住这一点——我们会继续讨论的。)

那《密码》杂志呢?让我们来查询归纳pinciple

> Check List_rect.
forall (A : Type) (P : List A -> Type),
   P (Empty A) ->
   (forall (a : A) (l : List A), P l -> P (Cons A a l)) ->
   forall l : List A, P l
让我看看。以上利用依赖类型:
P
取决于列表的实际值。如果
P list
是一个常量类型
B
,那么让我们手动简化它。我们获得:

forall (A : Type) (B : Type),
   B ->
   (forall (a : A) (l : List A), B -> B) ->
   forall l : List A, B
可以等效地写为

forall (A : Type) (B : Type),
   B ->
   (A -> List A -> B -> B) ->
   List A -> B
它是
foldr
,除了“当前列表”也被传递给二进制函数参数之外——这不是主要区别

现在,在Coq中,我们可以用另一种微妙不同的方式定义列表:

Inductive List2 : Type -> Type :=
  | Empty2: forall A, List2 A
  | Cons2 : forall A, A -> List2 A -> List2 A
.
它看起来是同一种类型,但有着深刻的区别。这里我们不是根据
列表A
来定义类型
列表A
。相反,我们是根据
List2
定义类型函数
List2:type->type
。这一点的要点是,对
List2
的递归引用不必应用于
A
——上面我们这样做的事实只是一个偶然事件

无论如何,让我们看看归纳原理的类型:

> Check List2_rect.
forall P : forall T : Type, List2 T -> Type,
   (forall A : Type, P A (Empty2 A)) ->
   (forall (A : Type) (a : A) (l : List2 A), P A l -> P A (Cons2 A a l)) ->
   forall (T : Type) (l : List2 T), P T l
> Check List3_rect.
forall P : forall T : Type, List3 T -> Type,
   (forall A : Type, P A (Empty3 A)) ->
   (forall (A : Type) (a : A) (l : List3 (A * A)), P (A * A) l -> P A (Cons3 A a l)) ->
   forall (T : Type) (l : List3 T), P T l
让我们像以前一样,从
p
中删除
List2 T
参数,基本上假设
p
是常量

forall P : forall T : Type, Type,
   (forall A : Type, P A ) ->
   (forall (A : Type) (a : A) (l : List2 A), P A -> P A) ->
   forall (T : Type) (l : List2 T), P T
等效重写:

forall P : (Type -> Type),
   (forall A : Type, P A) ->
   (forall (A : Type), A -> List2 A -> P A -> P A) ->
   forall (T : Type), List2 T -> P T
用Haskell表示法大致对应

(forall a, p a) ->                          -- Empty
(forall a, a -> List2 a -> p a -> p a) ->   -- Cons
List2 t -> p t
还不错——基本情况现在必须是多态函数,就像Haskell中的
Empty
一样。这是有道理的。类似地,归纳情况必须是多态函数,就像
Cons
一样。有一个额外的
list2a
参数,但是如果我们愿意,我们可以忽略它

现在,上面仍然是一种常规类型的折叠/折叠。非常规的呢?我要学习

data List a = Empty | Cons a (List (a,a))
在Coq中成为:

Inductive  List3 : Type -> Type :=
  | Empty3: forall A, List3 A
  | Cons3 : forall A, A -> List3 (A * A) -> List3 A
.
根据归纳原则:

> Check List2_rect.
forall P : forall T : Type, List2 T -> Type,
   (forall A : Type, P A (Empty2 A)) ->
   (forall (A : Type) (a : A) (l : List2 A), P A l -> P A (Cons2 A a l)) ->
   forall (T : Type) (l : List2 T), P T l
> Check List3_rect.
forall P : forall T : Type, List3 T -> Type,
   (forall A : Type, P A (Empty3 A)) ->
   (forall (A : Type) (a : A) (l : List3 (A * A)), P (A * A) l -> P A (Cons3 A a l)) ->
   forall (T : Type) (l : List3 T), P T l
删除“从属”部分:

在Haskell表示法中:

   (forall a. p a) ->                                      -- empty
   (forall a, a -> List3 (a, a) -> p (a, a) -> p a ) ->    -- cons
   List3 t -> p t
除了附加的
List3(a,a)
参数之外,这是一种折衷

最后,OP类型如何

data List a = Empty | Cons a (List (List a))
唉,Coq不接受这种类型

Inductive  List4 : Type -> Type :=
  | Empty4: forall A, List4 A
  | Cons4 : forall A, A -> List4 (List4 A) -> List4 A
.

由于内部
List4
事件并非处于严格的正位置。这可能是一个暗示,我应该停止懒惰,停止使用Coq来做这项工作,开始自己思考涉及的F-代数…;-)

多态递归绝对是不平凡的。作为中间步骤,您可能想添加一个不太极端的示例,即
数据列表A=Empty | Cons A(列表(A,A))
@chi谢谢!我认为
非正则递归类型
是我应该提到的一个术语-我调整了我问题的标题-我从不喜欢
这种类型
部分。我还将你的不太极端的例子加入到我的问题中。据我所知,折叠只为那些作为内函子F的初始代数出现的递归数据类型定义。我怀疑每个递归数据类型都是这种形式,因此每个数据类型都应该有折叠…无论如何,我不确定你的数据类型是否允许折叠这似乎很相关。