我试图通过搜索网页来了解FlexibleContexts扩展正在做什么,这些网页可以解释为凡人(例如,像我一样读过LYHFGG的人),但我没有找到任何这样的资源。
因此,我向专家们询问这个话题:有人可以解释一下这个扩展的作用,它为什么存在,并给出一两个简单的例子,说明如何以及为什么要使用它?
此外,如果我正在阅读其他人的代码which使用此扩展,那么为了理解使用此扩展编写的代码,我应该知道哪些扩展名?
如果没有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
必须是类型变量而不是具体类型。
通常它与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
这是a discussion。