私はFlexibleContexts拡張機能が何をしているのかを説明するWebページを検索して何をしているのかを理解しようとしていました(たとえば、私のようなLYHFGGを読んだ人)。そのようなリソースは見つかりませんでした。
そのためトピックについて専門家に質問します。この拡張機能の機能、存在する理由、および1つまたは2つの簡単な例を使用して、その理由を説明してください。使うべき?
さらに、誰か他の人のコードを読んでいる場合 which がこの拡張機能を使用している場合、拡張機能について知っておくべきことは何ですかこの拡張機能を使用して書かれたコードを理解していますか?
FlexibleContexts
がない場合、関数定義のすべての型クラス制約には型変数が必要です。例えば:
add :: Num a => a -> a -> a
add = (+)
ここで、a
はタイプ変数です。 FlexibleContexts
を有効にすると、型クラス内に任意の型を含めることができます。
intAdd :: Num Int => Int -> Int -> Int
intAdd = (+)
この例はかなり工夫されていますが、私が考えることができる最も簡単なものです。 FlexibleContexts
は通常、MultiParamTypeClasses
でのみ使用されます。次に例を示します。
class Shower a b where
myShow :: a -> b
doSomething :: Shower a String => a -> String
doSomething = myShow
ここでは、Shower a String
。 FlexibleContexts
がない場合、String
は具象型ではなく型変数でなければなりません。
一般的にはMultiParamTypeClasses
拡張子とともに使用されます。たとえば、mtl
ライブラリを使用する場合、次のように記述します。
doSomethingWithState :: MonadState MyState m => m ()
doSomethingWithState = do
current <- get
let something1 = computeSomething1 current
something2 = computeSomething2 current something1
put something2
同様に、MonadReader
とMonadWriter
を他の同様の型クラスとともに使用します。 FlexibleContexts
がないと、この制約を使用できません。
(この回答は @ DiegoNolan's に基づいていましたが、LYAH読者にとって意味のある既存のライブラリを使用するように書き直されました)。
言及されているものとは別に、その使用法を発見しました。GHCからのより明確なエラーメッセージが表示されます。例えば。通常は、
Prelude> max (1, 2) 3
<interactive>:1:1: error:
• Non type-variable argument in the constraint: Num (a, b)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall a b.
(Num (a, b), Num b, Num a, Ord b, Ord a) =>
(a, b)
そして、FlexibleContextsが有効になっている場合:
Prelude> max (1, 2) 3
<interactive>:1:1: error:
• No instance for (Num (Integer, Integer))
arising from a use of ‘it’
• In the first argument of ‘print’, namely ‘it’
In a stmt of an interactive GHCi command: print it
ディスカッション です。
FlexibleContexts
はタイプファミリーでよく使用されます。たとえば、GHC.Generics
を使用する場合、次のような署名が表示されるのが一般的です
foo :: (Generic a, GFoo (Rep a)) => Int -> a -> a
これは、MultiParamTypeClasses
の使用法のバリエーションと見なすことができます。
class (Generic a, rep ~ Rep a) => MPGeneric rep a
instance (Generic a, rep ~ Rep a) => MPGeneric rep a
mpFoo :: (MPGeneric rep a, GFoo rep) => Int -> a -> a
AJFarmarが指摘した のように、FlexibleContexts
は、MPTCでもタイプファミリーでも有用ではありません。以下に簡単な例を示します。
newtype Ap f a = Ap (f a)
deriving instance Show (f a) => Show (Ap f a)
Show1
を使用する別の方法は、かなり扱いにくいです。
より複雑な例は、AJFarmarのコメントによって提供されます。
data Free f a = Pure a | Free (f (Free f a))
deriving instance (Show a, Show (f (Free f a))) => Show (Free f a)
これは、再帰的であるため、UndecidableInstances
も取り込みますが、Free f a
を表示するために必要なものだけを説明するのに役立ちます。最先端のGHC Haskellでは、代わりにQuantifiedConstraints
を使用することもできます。
deriving instance (Show a, forall x. Show x => Show (f x)) => Show (Free f a)
しかし、Free f a
に適用されたf
のみを表示する必要があるため、これはやりすぎです。