ある意味では、それらは二重であるため、互いに非常に似ています。コンストラクターは、データ型のシグネチャ ファンクターの代数と考えることができ、同じファンクターの合体をパターン化します。
より明確にするために、考えてみましょう[]
。その署名関手はT_A X = 1 + A * X
or であり、Haskell では
type ListF a x = Maybe (a, x)
明白なFunctor
例で。キャリアListF
を持つ代数は単なるコンストラクタであることがわかりますList
-- general definition
type Algebra f a = f a -> a
consList :: Algebra (ListF a) [a]
consList Nothing = []
consList (Just (a, as)) = a:as
二重に、そのキャリアとしてのcoalgebraを見ることができListF
ますList
type Coalgebra f a = a -> f a
unconsList :: Coalgebra (ListF a) [a]
unconsList [] = Nothing
unconsList (a:as) = Just (a, as)
さらに、安全なバージョンのhead
とtail
が非常に自然なデストラクタであることを確認します。[]
headMay :: [a] -> Maybe a
headMay = fmap fst . unconsList
tailMay :: [a] -> Maybe a
tailMay = fmap snd . unconsList
これは個人的なペットの不満を煽り、部分性を無視して特に優れた関数でさえhead
ありtail
ません---それらは署名 functor を持つ無限リストでのみ自然ですT A X = A*X
。
Haskell では、ファンクターの最初Algebra
と最後Coalgebra
がそのファンクターの固定小数点として一致します。
newtype Fix f = Fix { unfix :: f (Fix f) }
これはまさにデータ型です。[a]
が同形であることを証明できますFix (ListF a)
fwd :: [a] -> Fix (ListF a)
fwd [] = Fix Nothing
fwd (a:as) = Fix (Just (a, fwd as))
bwd :: Fix (ListF a) -> [a]
bwd (Fix Nothing) = []
bwd (Fix (Just (a, fixed))) = a : bwd fixed
これにより、データ型自体をコンストラクターとパターンの両方として使用する正当な理由が得られますが、他の種類の「coalgebra のような」ものを作成すると、Sheやパターン コンビネーターによって提供されるような第一級のパターンを持つことができます。
パターンとコンストラクターの二重性をより深く理解するには、上記の演習を次のようなデータ型でもう一度実行してみてください。
data Tree a = Leaf | Branch (Tree a) a (Tree a)
その署名関手はT A X = 1 + X*A*X
or
type TreeF a x = Maybe (x,a,x)