Data.Constraint.Forall
提供了一些关于约束的量化,但是我没有看到如何使用它。请考虑以下事项:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Forall where
import Prelude
import Data.Constraint.Forall
class Monoid (f a) => MonoidalFunctor f a
testfun :: Forall (MonoidalFunctor f) => (a -> f a) -> [a] -> f a
testfun = foldMap
testfun' :: Monoid (f a) => (a -> f a) -> [a] -> f a
testfun' = foldMap
我认为testfun
会进行类型检查,因为Forall (MetaMonoid f)
会像forall a. Metamonoid f a
那样工作,因为超类约束而暗示forall a. Monoid (f a)
,但事实并非如此。
为什么它不起作用,是否有任何解决方法?我想避免为我的函数中的不同MyClass (f MyData)
类型编写许多约束,例如MyData
,我知道任何有用的f
都会有任何f MyData
的实例
答案 0 :(得分:4)
使用inst
inst :: forall p a. Forall p a :- p a
inst
见证了,如果您有forall a. p a
,那么您可以将a
设置为您想要的任何内容并获得p a
。
蕴涵(:-
)
newtype a :- b = Sub (a => Dict b)
data Dict a = a => Dict
因此,通过模式匹配,您可以在其中显示实例:
testfun :: forall f a. Forall (MonoidalFunctor f) => (a -> f a) -> [a] -> f a
testfun = case inst @(MonoidalFunctor f) @a of Sub Dict -> foldMap
(键入必要的应用程序/签名)或您可以使用(\\)
:
(\\) :: a => (b => r) -> a :- b -> r
testfun = foldMap \\ inst @(MonoidalFunctor f) @a
如果a
为真且值r
也需要b
为真,那么读取"后跟一个可以证明{{1}的值在给定b
的情况下,{}为a
。如果你重新安排一下
r
它看起来有点像功能组合。
这种舞蹈的原因仅仅是因为它超出了GHC的范围,推断(\\) :: (b => c) -> (a :- b) -> (a => c)
意味着它可以为任何Forall c
派生c a
;毕竟,这就是a
存在的原因。所以,你必须更明确一点。