0

値のタプルで自分自身を返す関数を作成しようとしています。基本的には、呼び出し元が変換された値を、新しい (カリー化された) バージョンの関数と共に取得して、処理でさらに使用するという考え方です。

しかし、現時点では、この関数のノーオペレーション (つまり何もしない) バージョンを考え出そうとして行き詰まっています。したがって、次のスニペットは明らかに問題ありません。これは、それ自体を返さないノーオペレーションです。

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 に関する多くの議論がありますが、私の問題に適用する方法がよくわかりません。

どんなアドバイスでも歓迎...

4

3 に答える 3

9

このようなものを表現するには、再帰型が必要です。Haskell はequirecursive 型をサポートしていないため、 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 マシンのように見えます。パッケージは同様のタイプをmachines エクスポートします。newtype Mealy i o = Mealy { runMealy :: i -> (o, Mealy i o) }

于 2013-08-15T09:23:10.297 に答える
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)
于 2013-08-15T14:41:43.150 に答える
1

@augustss が言おうとしていたことに答えるだけです。行く方法は、次のような再帰型を使用することです

data Foo a = Foo a (a -> Foo a)
noop :: a -> Foo a
noop a = Foo a noop
于 2013-08-15T09:23:11.937 に答える