Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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_Types_Lazy Evaluation - Fatal编程技术网

在haskell中,如何表示新定义的无限数据

在haskell中,如何表示新定义的无限数据,haskell,types,lazy-evaluation,Haskell,Types,Lazy Evaluation,我用以下方式在Haskell中定义了一个新的数据类型: data Pro = P Int Pro | Idle deriving Show 然后,我定义了一个适用于此新数据类型的运算符: (>*>) :: Pro -> Pro -> Pro Idle >*> ps = ps P i ps >*> qs = P i (ps >*> qs) 因此,infir=pridle>

我用以下方式在Haskell中定义了一个新的数据类型:

data Pro = P Int Pro | Idle
              deriving Show
然后,我定义了一个适用于此新数据类型的运算符:

(>*>) :: Pro -> Pro -> Pro
Idle        >*>   ps  = ps
P i ps      >*>   qs  = P i (ps >*> qs)
因此,
infir=pridle>*>(infi(r+1))
可以表示无限数据,如果我在终端中键入infi4 1,它将无限打印

后来,我意识到这个新的数据类型定义可以修改为:

data Try = T [Int] 
     deriving Show
它们非常相似,后者是一种列表,似乎更简单。 但当我定义以下无限数据时:

(>/>) :: Try -> Try -> Try
T []    >/>     i       = i 
T ts    >/>     T qs    = T (ts ++ qs )

infi2 r = (T [r]) >/> (infi2 r)
并试图在终端上打印,结果显示:

Exception: stack overflow
Haskell的lazy属性似乎无法在这种新数据类型上工作。是否有人可以告诉我原因以及如何按第二种数据类型打印无限数据。

您需要:

另外,您不需要第一个子句,因此
(>/>)
可以定义为

(>/>) :: Try -> Try -> Try
~(T ts) >/> ~(T qs) = T (ts ++ qs)
(>*>)
的定义是惰性的,因为在第二个参数上没有模式匹配

更新


正如@MigMit所建议的,您只需使用
newtype
,您对
(>/>)
的原始定义就可以了。请看一下
2的凌乱部分另一个答案是正确的,即正确的修复方法是使用
~
-模式(也称为无可辩驳的模式或惰性模式)或新类型,但让我们看看为什么

以下是您的定义供参考:

(>/>) :: Try -> Try -> Try
T []    >/>     i       = i 
T ts    >/>     T qs    = T (ts ++ qs)

infi2 r = T [r] >/> infi2 r -- I've omitted unnecessary parentheses
现在,如果调用
infi2 1
,将发生以下减少:

   infi2 1

=    { expanding the definition of infi2 }

   T [1] >/> infi2 1
这是重点。我们想减少最外层的功能, 这是
/>
。但我们必须决定哪种情况适用。这很容易 查看第一个不匹配,因为
T[1]
T[]
不匹配。然而,第二种情况要求
/>
的第二个参数的形状为
tqs
,我们有
infi2 1
。即使
Try
只有一个构造函数,GHC/Haskell也不会做出这样的飞跃。相反,它将进一步计算infi2 1的
。因此,下一个缩减步骤是

   T [1] >/> infi2 1

=    { expanding the definition of infi2 }

   T [1] >/> (T [1] >/> infi2 1)
现在我们又处于完全相同的情况。我们仍然不能减少最外层的
/>
,因为我们不知道正确参数的构造函数;因此,我们必须进一步降低这一比例。但在这方面,我们需要再次降低成本 右参数进一步了解内部
/>
右参数的构造函数:

   T [1] >/> (T [1] >/> infi2 1)

=    { expanding the definition of infi2 }

   T [1] >/> (T [1] >/> infi2 1)

=    { expanding the definition of infi2 }

   T [1] >/> (T [1] >/> (T [1] >/> infi2 1))

=    ...
这将无限期地继续,直到内存满为止。我们永远也做不到 真正的进步

再次回顾原始定义,(通过一点实践)实际上可以看到这一点,而无需进行整个扩展:

(>/>) :: Try -> Try -> Try
T []    >/>     i       = i 
T ts    >/>     T qs    = T (ts ++ qs)

infi2 r = T [r] >/> infi2 r
/>
定义的第二种情况下,只有在我们知道两个参数都是
T
s之后,我们才产生
T
。因此在
infi2r
中,我们只能在
infi2r
返回后减少外部
/>
,但这是一个递归调用

现在介绍解决此问题的解决方案:

使用新类型 与

T
上的模式匹配不再是
data
,而是成为禁止操作。新类型保证具有与基础类型相同的运行时表示形式(此处为
[Int]
),并且应用构造函数
T
或模式匹配对转换类型有影响,但在运行时没有影响

因此,一旦我们

T [1] >/> infi2 1
为了对其中一个案例做出决定,我们现在只看到第一个列表是非空的,因此第一个案例不适用。第二例为左侧

T ts >/> T qs = ...
在假设
T
上的模式匹配是一个noop的情况下,这是非常正确的,并且可以立即减少

使用
~
-模式 类似地,如果我们继续使用
数据
,但是

T ts >/> ~(T qs) = ...
我们改变了GHC/Haskell的行为,以实现我上面提到的“信仰的飞跃”。无可辩驳的模式匹配会自动成功,因此不会引起进一步的评估。对于单个构造函数数据类型,例如
Try
,这样做基本上是安全的。但是,如果在多构造函数数据类型上进行这种惰性模式匹配,结果发现匹配的值不是模式中出现的构造函数的值,那么匹配仍然会成功,并且一旦尝试使用模式内部的值,就会出现运行时异常

显式提取 第三种选择是编写提取函数

unT :: Try -> [Int]
unT (T ts) = ts
然后说

(>/>) :: Try -> Try -> Try
T []    >/>     i       = i 
T ts    >/>     qs      = T (ts ++ unT qs)
这表明我们对第二个论点没有任何期望 在模式匹配时。这个版本非常符合
~
-模式版本将编译到的内容

最后,让我们看看现在的降价情况:

   infi2 1

=    { expanding the definition of infi2 }

   T [1] >/> infi2 1

=    { expanding the definition of >/> }

   T ([1] ++ unT (infi2 1))
假设我们要打印结果并进行完全还原,让我们从这里继续一段时间:

   T ([1] ++ unT (infi2 1))

=    { expanding the definition of ++ }

   T (1 : unT (infi2 1))

=    { expanding the definition of infi2 }

   T (1 : unT (T [1] >/> infi2 1))

=    { expanding the definition of >/> }

   T (1 : unT (T ([1] ++ unT (infi2 1))))

=    { expanding the definition of the outer unT }

   T (1 : ([1] ++ unT (infi2 1)))

在这一点上,很明显我们确实是以递增的方式获得无限列表。

我建议使用
newtype
而不是
数据。
   infi2 1

=    { expanding the definition of infi2 }

   T [1] >/> infi2 1

=    { expanding the definition of >/> }

   T ([1] ++ unT (infi2 1))
   T ([1] ++ unT (infi2 1))

=    { expanding the definition of ++ }

   T (1 : unT (infi2 1))

=    { expanding the definition of infi2 }

   T (1 : unT (T [1] >/> infi2 1))

=    { expanding the definition of >/> }

   T (1 : unT (T ([1] ++ unT (infi2 1))))

=    { expanding the definition of the outer unT }

   T (1 : ([1] ++ unT (infi2 1)))