web-dev-qa-db-ja.com

FlexibleContexts拡張機能は何に適していますか?簡単な例を使って説明してください。

私はFlexibleContexts拡張機能が何をしているのかを説明するWebページを検索して何をしているのかを理解しようとしていました(たとえば、私のようなLYHFGGを読んだ人)。そのようなリソースは見つかりませんでした。

そのためトピックについて専門家に質問します。この拡張機能の機能、存在する理由、および1つまたは2つの簡単な例を使用して、その理由を説明してください。使うべき?

さらに、誰か他の人のコードを読んでいる場合 which がこの拡張機能を使用している場合、拡張機能について知っておくべきことは何ですかこの拡張機能を使用して書かれたコードを理解していますか?

36
jhegedus

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 StringFlexibleContextsがない場合、Stringは具象型ではなく型変数でなければなりません。

55
DiegoNolan

一般的にはMultiParamTypeClasses拡張子とともに使用されます。たとえば、mtlライブラリを使用する場合、次のように記述します。

doSomethingWithState :: MonadState MyState m => m ()
doSomethingWithState = do
    current <- get
    let something1 = computeSomething1 current
        something2 = computeSomething2 current something1
    put something2

同様に、MonadReaderMonadWriterを他の同様の型クラスとともに使用します。 FlexibleContextsがないと、この制約を使用できません。

(この回答は @ DiegoNolan's に基づいていましたが、LYAH読者にとって意味のある既存のライブラリを使用するように書き直されました)。

8
bheklilr

言及されているものとは別に、その使用法を発見しました。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

ディスカッション です。

5
Dogweather

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のみを表示する必要があるため、これはやりすぎです。

1
dfeuer