この最近の私の回答では、たまたまこの古い栗を割って開けました (非常に古いプログラムで、その半分は 17 世紀にライプニッツによって書かれ、70 年代に私の父によってコンピューター上で書かれました)。スペースを節約するために、最新のビットは省略します。
class Differentiable f where
type D f :: * -> *
newtype K a x = K a
newtype I x = I x
data (f :+: g) x = L (f x)
| R (g x)
data (f :*: g) x = f x :&: g x
instance Differentiable (K a) where
type D (K a) = K Void
instance Differentiable I where
type D I = K ()
instance (Differentiable f, Differentiable g) => Differentiable (f :+: g) where
type D (f :+: g) = D f :+: D g
instance (Differentiable f, Differentiable g) => Differentiable (f :*: g) where
type D (f :*: g) = (D f :*: g) :+: (f :*: D g)
さて、ここでイライラすることがあります。それ自体が微分可能でD f
なければならないことを規定する方法がわかりません。確かに、これらのインスタンスはその性質を尊重しており、ファンクタを微分し続け、より多くの場所で穴をあける機能を利用する楽しいプログラムを作成できる可能性があります: テイラー展開など。
みたいなことが言えるようになりたいです
class Differentiable f where
type D f
instance Differentiable (D f)
インスタンス宣言type
に、必要なインスタンスが存在する定義があることを確認する必要があります。
多分もっとありふれたもの
class SortContainer c where
type WhatsIn c
instance Ord (WhatsIn c)
...
もいいでしょう。もちろん、それにはfundepの回避策があります
class Ord w => SortContainer c w | c -> w where ...
しかし、同じトリックを試みるのDifferentiable
は...まあ...面倒です。
それで、再現可能な微分可能性を得る気の利いた回避策はありますか?(表現GADT and and and and ...を構築できると思いますが、クラスで機能する方法はありますか?)
また、宣言時に型 (およびおそらくデータ) ファミリに対して制約を要求し、インスタンスがそれらを満たすことを確認できるようにする必要があるという提案に、明らかな障害はありますか?