Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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 如何获取依赖类型的间隔的长度?_Haskell_Dependent Type - Fatal编程技术网

Haskell 如何获取依赖类型的间隔的长度?

Haskell 如何获取依赖类型的间隔的长度?,haskell,dependent-type,Haskell,Dependent Type,假设我有一个数据类型 data Interval :: Nat -> Nat -> * where Go :: Interval m n -> Interval m (S n) Empty :: SNat n -> Interval n n 这是半(右)开区间Nat是标准的归纳自然,SNat是相应的单态 现在我想得到一个给定间隔长度的singletonNat: intervalLength :: Interval n (Plus len n) -> SNa

假设我有一个数据类型

data Interval :: Nat -> Nat -> * where
  Go :: Interval m n -> Interval m (S n)
  Empty :: SNat n -> Interval n n
这是半(右)开区间
Nat
是标准的归纳自然,SNat是相应的单态

现在我想得到一个给定间隔长度的singleton
Nat

intervalLength :: Interval n (Plus len n) -> SNat len
intervalLength Empty = Z
intervalLength (Go i) = S (intervalLength i)
这不起作用,因为
Plus
函数不是内射函数。我可以这样定义它

intervalLength :: Interval m n -> SNat (Minus n m)
但我想这需要一些引理(和附加约束)。而且,我的间隔出现在前一个形状

背景:我试着用欧米茄做这个,但没有成功()

还有,这些问题是如何用改进的打字机来解决的?LHS模式的RHS能否为LHS模式的类型方程提供关键提示,从而消除非注入性


Agda程序员如何解决这些问题?

这是我的程序版本。我正在使用

{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeFamilies #-}
我有
Nat
和它的singleton

data Nat = Z | S Nat

data SNat :: Nat -> * where
  ZZ :: SNat Z
  SS :: SNat n -> SNat (S n)
我更熟悉您的
Interval
类型,它是“小于或等于”的“后缀”定义:“后缀”,因为如果您从数字升级到列表,并用元素标记每个
S
,您就有了列表后缀的定义

data Le :: Nat -> Nat -> * where
  Len :: SNat n -> Le n n
  Les :: Le m n -> Le m (S n)
这是补充

type family Plus (x :: Nat) (y :: Nat) :: Nat
type instance Plus Z     y  = y
type instance Plus (S x) y  = S (Plus x y)
现在,您的难题是计算一些
Le
-值中的
Les
构造函数,提取其索引之间的差异。与其假设我们正在处理一些
len(加mn)
并试图计算
snatm
,我将编写一个函数来计算任意
lemo
索引之间的差异,并建立与
Plus
的连接

这里是
Le
的附加定义,提供了单例

data AddOn :: Nat -> Nat -> * where
  AddOn :: SNat n -> SNat m -> AddOn n (Plus m n)
我们可以很容易地确定
Le
意味着
AddOn
。一些
AddOn n o
上的模式匹配显示
o
对于一些
m
来说是
加mn
,并将我们想要的单件交给我们

leAddOn :: Le m o -> AddOn m o
leAddOn (Len n) = AddOn n ZZ
leAddOn (Les p) = case leAddOn p of AddOn n m -> AddOn n (SS m)
更一般地说,我建议制定依赖类型的编程问题,最小化您计划匹配的类型索引中定义函数的存在。这避免了复杂的统一。(用于将此类功能涂成绿色的警句,因此建议“不要碰绿色粘液!”)
Le n o
,事实证明(这就是
leAddOn
)的要点),它的信息量不亚于
Le n(加上m n)
,但它更容易匹配


但更一般地说,设置一个相关数据类型是一种非常正常的体验,它捕获了问题的逻辑,但处理起来绝对可怕。这并不意味着所有捕获正确逻辑的数据类型都将是绝对可怕的,只是你需要更仔细地考虑你定义的人体工程学。将这些定义简洁明了并不是很多人在普通函数式编程学习经验中学会的技能,因此希望能够攀登一条新的学习曲线。

我在Idris中尝试过这一点。虽然我同意pigworker关于重新制定问题的建议,但以下是您必须做的事情,以使您的定义通过Idris类型检查器。首先,单身NAT:

data SNat : Nat -> Set where
   ZZ : SNat O
   SS : SNat k -> SNat (S k)
然后,间隔的定义:

data Interval : Nat -> Nat -> Set where
  Go : Interval m n -> Interval m (S n)
  Empty : SNat n -> Interval n n
您想要的intervalLength定义有点像这样:

intervalLength : Interval n (plus len n) -> SNat len
intervalLength (Empty sn) = ZZ
intervalLength (Go i)     = SS (intervalLength i)
但是您会遇到麻烦,因为正如您所说的,
plus
不是内射的。我们可以通过明确地在
len
上进行额外的模式匹配来达到目的-然后统一可以取得一些进展:

intervalLength : Interval n (plus len n) -> SNat len
intervalLength {len = O}   (Empty sn) = ZZ
intervalLength {len = S k} (Go i)     = SS (intervalLength i)
这很好,并通过了typechecker,但不幸的是,它不相信函数是total:

*interval> :total intervalLength
not total as there are missing cases
丢失的案例是:

intervalLength {len = O}   (Go i)     = ?missing
如果您尝试此操作,并询问REPL缺少的
类型,您将看到:

missing : (n : Nat) -> (i : Interval (S n) n) -> SNat O
现在,我们知道type
Interval(sn)n
是空的,但是遗憾的是,type checker没有。不知何故,我们需要编写
badInterval:Interval(sn)n->124; u
,然后我们可以说:

intervalLength {len = O}   (Go i)     = FalseElim (badInterval i)

我将把
badInterval
的定义留作练习:-)。这并不特别棘手,但有点无聊——有时很难避免使用这类类型,但实现
badInterval
支持pigworker不这样做的建议

当然,还有一个问题,为什么要费心在Idris中定义单例NAT。当然,你已经有了
len
!当以全谱依赖类型语言呈现时,最初表述的问题确实非常奇怪。