web-dev-qa-db-ja.com

Ed Kmettの再帰スキームパッケージのFix、Mu、Nuの違いは何ですか

EdKmettのrecursion-schemeパッケージには、次の3つの宣言があります。

newtype Fix f = Fix (f (Fix f))

newtype Mu f = Mu (forall a. (f a -> a) -> a)

data Nu f where 
  Nu :: (a -> f a) -> a -> Nu f

これらの3つのデータ型の違いは何ですか?

25
hgiesel

Muは再帰型をその折り畳みとして表し、Nuはそれを展開として表します。 Haskellでは、これらは同型であり、同じタイプを表すさまざまな方法です。 Haskellに任意の再帰がないふりをすると、これらのタイプの違いがより興味深いものになります。_Mu f_はfの最小(初期)不動点であり、_Nu f_はその不動点です。最大(終端)固定小数点。

fの不動点は、タイプTTと_f T_の間の同型、つまり、逆関数_in :: f T -> T_、_out :: T -> f T_。型Fixは、Haskellの組み込み型再帰を使用して、同型を直接宣言します。ただし、MuNuの両方にin/outを実装できます。

具体的な例として、再帰的な値を記述できないふりをします。 _Mu Maybe_の住民、つまり値:: forall r. (Maybe r -> r) -> rは、自然、{0、1、2、...}です。 _Nu Maybe_の住民、つまり値:: exists x. (x, x -> Maybe x)は、conaturals {0、1、2、...、∞}です。これらのタイプの可能な値について考えて、_Nu Maybe_に余分な住民がいる理由を確認してください。

これらのタイプの直感を知りたい場合は、再帰せずに(おおまかに難易度の高い順に)以下を実装するのは楽しい演習になる可能性があります。

  • _zeroMu :: Mu Maybe_、_succMu :: Mu Maybe -> Mu Maybe_
  • _zeroNu :: Nu Maybe_、_succNu :: Nu Maybe -> Nu Maybe_、_inftyNu :: Nu Maybe_
  • _muTofix :: Mu f -> Fix f_、_fixToNu :: Fix f -> Nu f_
  • inMu :: f (Mu f) -> Mu foutMu :: Mu f -> f (Mu f)
  • inNu :: f (Nu f) -> Nu foutNu :: Nu f -> f (Nu f)

これらの実装を試みることもできますが、再帰が必要です。

  • _nuToFix :: Nu f -> Fix f_、_fixToMu :: Fix f -> Mu f_

_Mu f_は最小不動点であり、_Nu f_は最大であるため、関数_:: Mu f -> Nu f_の記述は非常に簡単ですが、関数_:: Nu f -> Mu f_の記述は困難です。それは流れに逆らって泳ぐようなものです。

(ある時点で、これらのタイプのより詳細な説明を書くつもりでしたが、この形式には少し長すぎるかもしれません。)

27
shachaf