在Haskell中使用Forall

时间:2017-12-20 14:58:07

标签: haskell

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的实例

1 个答案:

答案 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存在的原因。所以,你必须更明确一点。