4

ライブラリを使用するHaskellプログラムがあると想像してください。プログラムは、依存関係の1つからタイプTのタイプクラスTCインスタンスを提供します。同じライブラリの次のバージョンでは、ライブラリの作成者がタイプTのタイプクラスTCの別のインスタンスを提供しました。

両方の型クラスインスタンスを使用したいと思います。どうすればそうできますか?

PSニュータイプソリューションは機能しません。どちらのインスタンスも、私たちが管理していないライブラリに存在します。

PPS実際のコードの例はありません。それは理論的な質問です。型クラスがライブラリの構成可能性とどのように機能するかを学びたいだけです。

4

5 に答える 5

5

Haskell2010レポート§4.3.2は次のように述べています

  • 型は、プログラム内で特定のクラスのインスタンスとして複数回宣言することはできません。

したがって、標準のHaskellでは不可能です。

私はあなたがGHCでこれを行うことを可能にするGHC拡張を知りません。

これが(1つ?)孤立したインスタンス(型と型クラスの両方とは異なるモジュールでインスタンスを定義する)が一般的に悪い考えと見なされる理由です。

于 2013-02-10T11:44:19.843 に答える
4

一般に、同じ型に対して複数の型クラス インスタンスを作成することはできません。ただし、タイプが別のパッケージまたは同じパッケージの古いバージョンで定義されている場合、ghc はそれを別のタイプと見なします。したがって、理論的には、それに対してインスタンスをfoo-1.1定義し、インスタンスを定義して、2 つを一緒に使用することができます。Foofoo-1.2Foo

ただし、実際には、これはうまく機能しません。関数は、いずれかのタイプでのみ機能します。で動作する関数を作成すると、両方ではなく、Foo特定の 1 つのみで動作します。Foo基本的に、2 つの完全に別個の議論の余地のないタイプがあります。構築するのがどれほど厄介であるかとは完全に別物であり、使用するのは厄介です。

于 2013-02-10T11:49:21.737 に答える
3

より優れた柔軟性と構成可能性が必要な場合は、型クラスをレコードとして具体化します。RankNTypes必要な場合があります。

たとえば、Applicative 型クラスを具体化する方法は次のとおりです。

{-# LANGUAGE RankNTypes #-}

data ApplicativeInstance f = ApplicativeInstance
  { pure :: forall a. a -> f a
  , amap :: forall a b. (a -> b) -> f a -> f b
  , ap :: forall a b. f (a -> b) -> f a -> f b
  }


listApplicative = ApplicativeInstance
  { pure = \a -> [a]
  , amap = map
  , ap = \fs xs -> case fs of
      [] -> []
      f:fs' -> map f xs ++ ap cartesianListApplicative fs' xs
  }


zipListApplicative = ApplicativeInstance
  { pure = \a -> [a]
  , amap = map
  , ap = \fs xs -> case (fs, xs) of
      ([], _) -> []
      (_, []) -> []
      (f:fs', x:xs') -> f x : ap zipListApplicative fs' xs'
  }

これで、必要なインスタンスを指定できるようになりました。ただし、インスタンスを暗黙的に選択する力は失われます。選択は明示的に行う必要があります。

ghci> ap listApplicative [(+1), (*3)] [1 .. 5]
[2,3,4,5,6,3,6,9,12,15]
ghci> ap zip
zip                 zipListApplicative  zipWith3
zip3                zipWith
ghci> ap zipListApplicative [(+1), (*3)] [1 .. 5]
[2,6]

参照: http://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/

于 2013-02-13T21:48:48.397 に答える
3

Cabal を使用すると、同じライブラリの 1 つのバージョンにしか依存できないと断言できます。

インスタンスの代替バージョンのソース コードをプロジェクトに少なくともコピー アンド ペーストすることは可能ですが、モジュールごとにインポートできるのは 1 つだけです。競合するインスタンスをモジュールにインポートすると、実用的な解決策がない決定不能なインスタンスの問題にぶつかります。

実を言うと、同じライブラリによって発行された同じ型に対して、同じクラスの異なるインスタンスを持ちたいと思う理由が想像できません。非常に実用的ではないようです。あなたの状況で何が役立つかについての私の推測は、インスタンスに応じた2つの型クラスを持つことです.1つはライブラリの現在のバージョンからのもので、もう1つは古いバージョンの名前が変更されたソースコードのコピーです。

于 2013-02-10T11:33:52.953 に答える
2

依存関係ツリーで同じパッケージの異なるバージョンとリンクすることは、依存関係の競合につながるため、現時点では不可能です。

しかし、このGHCステータス更新ビデオで述べられているように、同じライブラリで1つのバージョンのみが使用されている限り、これは将来可能になると思います.

于 2013-02-10T14:02:36.357 に答える