在haskell中返回自引用函数时无限类型错误

时间:2013-08-15 09:09:36

标签: haskell infinite

我正在尝试创建一个在值元组中返回自身的函数。基本上,这个想法是调用者将获得转换后的值,以及函数的新(curried)版本,以便在处理过程中进一步使用。

然而,目前,我一直试图想出这个功能的无操作(即无所事事)版本。所以下面的片段显然很好 - 这是一个不能自行返回的无操作:

noOp s as xs = (s, as, xs)

但如果我改为:

noOp s as xs = (s, as, xs, noOp)

我收到“无限类型”错误:

Occurs check: cannot construct the infinite type:
  t3 = t0 -> t1 -> t2 -> (t0, t1, t2, t3)
In the expression: noop
In the expression: (s, as, xs, noop)
In an equation for `noop': noop s as xs = (s, as, xs, noop)

关于处理无限类型错误的SO有很多讨论 - 但我无法弄清楚如何应用我的问题。

欢迎任何建议......

3 个答案:

答案 0 :(得分:9)

要表达这样的东西,你需要一个递归类型。由于Haskell不支持equirecursive types,因此您需要使用newtype / data

因此,您可以定义newtype Foo s = Foo { runFoo :: s -> (s, Foo s) },然后编写noOp :: Foo (A,B,C); noOp = Foo (\(a,b,c) -> ((a,b,c), noOp))

这看起来像Mealy machine。包machines exports包类似:newtype Mealy i o = Mealy { runMealy :: i -> (o, Mealy i o) }

答案 1 :(得分:1)

回答@augustss试图说的话。要走的路是使用像

这样的递归类型
data Foo a = Foo a (a -> Foo a)
noop :: a -> Foo a
noop a = Foo a noop

答案 2 :(得分:1)

你面临的问题是你有一个无限递归的类型!类型

的意思是noOp
noOp :: a -> b -> c -> (a,b,c,a -> b -> c -> (a,b,c,a -> b -> c -> (a,b,c,...))))

正如您所看到的,我们永远无法完全写出noOp的类型,因为它依赖于它 关于noOp的类型。如果我们只能封装noOp的类型 按名称引用它。

但事实上,我们可以做到这一点!

data Foo a b c = Foo (a -> b -> c -> (a,b,c,Foo a b c))

如您所见,捕获递归是因为我们引用了类型 按Foo a b c。现在有必要包装和解包:

runFoo (Foo f) = f

noOp s as xs = Foo (s, as, xs, noOp)

现在,我同意,这似乎有点不方便,但对于真正的应用你 可能会找到一个比Foo更合适的数据结构来保存你的 值,可能是

的内容
data Bar s as xs = Bar s as xs (Bar s as xs)