Haskell中的幻像类型

时间:2016-09-01 10:04:15

标签: haskell phantom-types

这是我的问题的简化版本。

我有一个递归数据结构(Stream1)。当我介绍幻像类型(流a)时,递归描述(即t1)不再有效。另一方面,t2通过创建无限结构而工作正常,因为它直接使用Stream1。我需要使用构造函数preI,例如在t1中。我错过了什么?我需要t1表现得像t2 - 也就是说,返回一个无限的流。

data Stream a = Stream Stream1
  deriving (Eq, Show)

data Stream1 = PreI Integer Stream1
  deriving (Eq, Show)

preI :: Integer -> Stream Int -> Stream Int
preI n (Stream s) = Stream (PreI n s)

t1 :: Stream Int
t1 = let x = preI 0 x
     in x

t2 :: Stream Int
t2 = let x = PreI 0 x
     in Stream x

1 个答案:

答案 0 :(得分:6)

preI :: Integer -> Stream Int -> Stream Int
preI n (Stream s) = ...
    -- ^^^^^^^^^^

此模式匹配在生成任何输出之前强制参数。对于流,这很糟糕,因为它将最不固定的点保持在底部(非终止)而不是无限流。

您可以尝试使用lazy / irrefutable模式匹配:

preI :: Integer -> Stream Int -> Stream Int
preI n ~(Stream s) = Stream (PreI n s)
    -- ^

这实质上意味着:

preI :: Integer -> Stream Int -> Stream Int
preI n z = Stream (PreI n s)
    where s = case z of Stream x -> x

首先在输出中生成Stream, PreI,然后才开始展开其输入(在使用s时发生)。

或者,更好的是,将Streamdata更改为newtype:这样,模式匹配将始终是懒惰的。实际上,使用newtype我们在运行时不再有任何包装,模式匹配实际上是无操作。