FlexibleContexts 扩展有什么用?你能用一个简单的例子解释一下吗?
What is the FlexibleContexts extension good for? Could you please explain it using a simple example?
我试图通过搜索网页来了解 FlexibleContexts 扩展在做什么,这些网页可以向普通人(例如像我一样读过 LYHFGG 的人)解释它,但我没有找到任何此类资源。
因此请教专家:能否解释一下这个扩展的作用,为什么存在,并举一两个简单的例子说明应该如何使用以及为什么要使用是吗?
此外,如果我正在阅读别人的代码 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
你不能使用这个约束。
(请注意,此答案基于 ,但改写为使用对 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。
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
与 一样,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
。
我试图通过搜索网页来了解 FlexibleContexts 扩展在做什么,这些网页可以向普通人(例如像我一样读过 LYHFGG 的人)解释它,但我没有找到任何此类资源。
因此请教专家:能否解释一下这个扩展的作用,为什么存在,并举一两个简单的例子说明应该如何使用以及为什么要使用是吗?
此外,如果我正在阅读别人的代码 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
你不能使用这个约束。
(请注意,此答案基于
除了上面提到的那些之外,我还发现了它的另一个用途:它可以使 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。
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
与 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
。