具体的には、J の共役演算子 (g&.f = (f inverse)(g)(f)) に触発されて、関数に追加情報を追加する方法が必要です。明白な方法は、ADT を使用することです。何かのようなもの:
data Isomorphism a b = ISO {FW (a -> b) , BW (b -> a)}
(FW f) `isoApp` x = f x
(BW g) `isoApp` x = g x
しかし、ほとんどの場合 forward 関数だけが必要な場合、アプリケーション関数が必要になると、コードの可読性が大幅に低下します。非常に便利なのはクラスです:
class Applyable a b c | a b -> c where
apply :: a -> b -> c
( b は存在量指定子で暗黙的にできると思いますが、署名が間違っていないことを確認できるほど快適ではありません)
これで適用が暗黙的になるため、次のように書くことができます
f x
他の機能と同じように。元:
instance Applyable (a -> b) a b where
apply f x = f x
instance Applyable (Isomorphism a b) a b where
apply f x = (FW f) x
inverse (Iso f g) = Iso g f
次に、次のように記述できます。
conjugate :: (Applyable g b b) => g -> Iso a b -> b -> a
f `conjugate` g = (inverse f) . g . f
理想的には、型シグネチャを推論できます
ただし、関数ではなく Applyable をサポートするには (.) も変更する必要があるため、これらのセマンティクスは複雑に見えます。型システムをだまして、適用可能なデータ型をすべての通常の目的で関数として扱うようにする方法はありますか? これが不可能/悪い考えである根本的な理由はありますか?