繁体   English   中英

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

[英]What is the FlexibleContexts extension good for? Could you please explain it using a simple example?

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

因此,我向该主题的专家请教:能否请您解释一下这个扩展的作用,它为什么存在,并给出一两个简单的例子,如何以及为什么应该使用它?

此外,如果我读别人的代码,其使用这个扩展名,那我怎么知道,以了解使用此扩展编写的代码扩展?

如果没有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

MonadReaderMonadWriter以及其他类似的类型类类似。 如果没有FlexibleContexts您将无法使用此约束。

(请注意,此答案基于@DiegoNolan 的答案,但已重写为使用对 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 fa 在前沿的 GHC Haskell 中,另一种选择是使用QuantifiedConstraints

deriving instance (Show a, forall x. Show x => Show (f x)) => Show (Free f a)

但这有点矫枉过正,因为我们只需要显示应用于Free fa f

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM