使用存在

时间:2013-01-11 16:51:29

标签: haskell

我正在阅读这篇优秀论文"Functional Programming with Structured Graphs, Bruno C. d. S. Oliveira"some video here),我正试图实现所有结构。我正在努力使用存在感。尽管作者提到了Haskell throghout,但似乎这些类型更容易用Coq或Agda表达。我怎样才能编译?感谢。

代码

data PStream a v = Var v
                 | Mu (v -> PStream a v)
                 | Cons a (PStream a v)

data Stream a = forall v. Pack {pop :: PStream a v} 


foldStream :: (a -> b -> b) -> b -> Stream a -> b
foldStream f k (Pack s) = pfoldStream s
    where pfoldStream (Var x)     = x
          pfoldStream (Mu g)      = pfoldStream (g k)
          pfoldStream (Cons x xs) = f x (pfoldStream xs)

错误

error:
 Couldn't match type `v' with `b'
      `v' is a rigid type variable bound by
          a pattern with constructor
            Pack :: forall a v. PStream a v -> Stream a,
          in an equation for `foldStream'
          at C:\...\StructuredGraph.hs:17:17
      `b' is a rigid type variable bound by
          the type signature for
            foldStream :: (a -> b -> b) -> b -> Stream a -> b
          at C:\...\StructuredGraph.hs:17:1
    Expected type: PStream a b
      Actual type: PStream a v
    In the first argument of `pfoldStream', namely `s'
    In the expression: pfoldStream s

3 个答案:

答案 0 :(得分:6)

你有一个存在主义类型,但看起来文中提到的类型是通用的(虽然我没有超出Stream的定义阅读它。)

之间存在很大差异
newtype Stream a = forall v. Pack { pop :: PStream a v }

newtype Stream a = Pack { forall v. pop :: PStream a v }

前者对这种类型似乎没有用,因为你无法知道v是什么。后者使你的代码编译。

答案 1 :(得分:4)

那么,您认为这个(部分)函数的类型是什么?

pfoldStream (Var x) = x

很简单:

pfoldStream :: Stream a v -> v

您的foldStream f k操作基本上计算pfoldstream . pop。这种类型是什么?

-- this is wrong
pfoldstream . pop :: PStream a -> v

你做不到。你不能只从存在主义内部返回类型。请注意右侧是否有v。我们怎么知道正确的v是什么?我们没有,因为v是存在限定的:类型检查器唯一的信息是类型v存在,它没有关于该类型是否等于b的信息

我可以举一个简单的说明:

data E = forall a. E a
unpack (E x) = x

在Haskell的类型系统中,unpack的类型不可表达,这基本上就是你所要求的。类型为unpack :: E -> x,但不适用于任何 x(x未通用量化),但对于特定 x(x是存在量化的)。< / p>

解决问题

下一个问题是“如何编译?”这不是问题 - 问题是请求不明确。我不知道你想要什么比编译器更多。我可以建议一种方法来编译:

foldStream :: (a -> b -> b) -> b -> PStream a b -> b
foldStream f k s = pfoldStream s
    where pfoldStream (Var x)     = x
          pfoldStream (Mu g)      = pfoldStream (g k)
          pfoldStream (Cons x xs) = f x (pfoldStream xs)

这摆脱了存在主义限定词,但我不知道该怎么做,我猜它不是你想要的。另一种使其编译的方法是用一个通过用户的扬声器播放“O Canada”的函数替换代码,但我怀疑它与你想要的相比没有上面的代码。

阅读论文

我查看了论文,我不认为该类型应该是存在的:我认为你应该使用更高阶的类型。所以不是存在主义类型:

data Stream a = forall v. Pack {pop :: PStream a v} 

我们真的在看第2级类型:

type Stream a = forall v. Stream a v

您可以在4.1节中看到v变量用于将流提供给自身的方式。这是通用的原因是因为它允许流的使用者使用v的任何类型,因此,v不需要出现在foldStream的签名中。

答案 2 :(得分:3)

每个人似乎都立刻回答了。我只是要指出GADT语法与下面的Str一样,总是让我更容易理解 - 在这种情况下,为什么foldStream对于量词的另一种方式是没有希望的。我有一个准可读的文件代码版本,所以我把它放在这里:https://github.com/applicative/structured_graphs

{-#LANGUAGE GADTs, RankNTypes#-}
data PStream a v = Var v
                 | Mu (v -> PStream a v)
                 | Cons a (PStream a v)
ones :: PStream Int v
ones = Cons (1 :: Int) ones

data Stream a where P :: forall a  . (forall v . PStream a v) -> Stream a

- 即我们使用(难以构造的)v独立PStream v - 类型为forall v . PStream a v的项目来生成Str a。因此P ones ones定义如上所述,因为我没有使用v来定义它。相比之下,与你的

data Stream a where P :: forall a v .      PStream a v        -> Stream a 

P的类型会让我们构建一个Str a,其中包含任何旧的a和v,甚至v的类型在生成的Str a中也是不可见的。所以P "Hello"将是此类型的有效成员。如果类型b专门用于Int而不是String,那么下面提取x的运气真好:

foldStream  :: (a -> b -> b) -> b -> Stream a -> b
foldStream f k = pfoldStream . pop
    where pfoldStream (Var x)     = x
          pfoldStream (Mu g)      = pfoldStream (g k)
          pfoldStream (Cons x xs) = f x (pfoldStream xs)
          pop (P x) = x

使用Stream的第一个(预期)声明,值很难构建,但易于使用。使用另一个(&#34;存在主义&#34;)声明,很容易构造一个值但很难使用它,因为底层类型是隐藏的&#39;。您在尝试定义pfoldStream时遇到了使用此类值的困难。