什么是FlexibleContexts扩展适合?你能用一个简单的例子解释一下吗?

时间:2015-07-06 16:37:16

标签: haskell ghc

我试图通过搜索可以向凡人(例如像我一样阅读过LYHFGG的人)解释它的网页来了解FlexibleContexts扩展正在做什么,但我没有找到任何这样的资源。

因此我向专家们询问这个话题:有人可以解释这个扩展的作用,为什么存在,并给出一两个简单的例子,说明如何以及为什么要使用它?

此外,如果我正在阅读其他人的代码which使用此扩展程序,那么为了理解使用此扩展程序编写的代码,我应该了解哪些扩展程序?

4 个答案:

答案 0 :(得分:51)

如果没有FlexibleContexts,函数定义中的所有类型类约束都必须具有类型变量。例如:

add :: Num a => a -> a
add = (+)

其中a是类型变量。启用FlexibleContexts后,您可以在类型类中包含任何类型。

intAdd :: Num 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,则必须是类型变量而不是具体类型。

答案 1 :(得分:6)

通常它与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读者有意义的现有库。)

答案 2 :(得分:3)

除了上面提到的那些以外,我还发现了它的用途:它会导致来自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

这里是Provisioning Actions and Touchpoints

答案 3 :(得分:1)

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 pointed out一样,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)

但这太过分了,因为我们只需要证明将f应用于Free f a