[英]How do I use Data.Constraint to reify constraints?
我有类型的功能
(forall m. (MonadCo r m, MonadReader Int m) => m ())
-> (forall m. (MonadCo r m, MonadReader Int m) => m ())
( MonadCo
是我自己的类角度代表一个协程monad。如果你喜欢你可以考虑MonadError em
的情况。问题将是相同的。)
看起来我应该能够重新定义约束并最终得到类型签名的函数
(Equals k (MonadCo r, MonadReader Int))
=> (Constrain k ()) -> (Constrain k ())
但我不知道如何在实践中实现这一点。 我对以下内容感到困惑:-
和:=>
实际上是。 我想我还需要一个Forall1
在那里,因为我普遍量化m
,但我不知道它应该适合哪里。
真正想要做的就是重新实现这一目标forall m. (MonadCo rm, MonadReader Int m)
forall m. (MonadCo rm, MonadReader Int m)
约束。 我认为,当我这样做时,左边出现的任何结果都将自动成为“正确的东西”。
Data.Constraint
似乎非常强大,但我无法找到从哪里开始。
似乎不可能。 看起来你的“Implies”在k中是逆变的,而你想要的功能则不会。
我的意思是,如果你有一些奇怪的MonadFoo m
类,你会定义
type k m = (MonadCo r m, MonadReader Int m, MonadFoo m)
假设这个类是专门设计的,这个类只有一个实例(好吧,如果你不至少使用GeneralizedNewtypeDeriving
),一些monad MMM
,它也是MonadCo r
和MonadReader Int
一个实例。 。 然后你的类型Constrain k ()
可能与MMM ()
同构。 所以,你想要一个函数MMM () -> MMM ()
- 但是输入类型MMM ()
比你的函数工作所需要的要弱得多。 您不可能以这种方式概括您的功能。
更新:
一些快乐的Oleg'ing,我们有以下代码:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Forall where
import Control.Monad.Reader
class Monad m => MonadCo r m where
scary ::
(forall m. (MonadCo r m, MonadReader Int m) => m ()) ->
(forall m. (MonadCo r m, MonadReader Int m) => m ())
scary = undefined -- here goes your original function
class Equals (d1 :: (* -> *) -> *) d2 where
equals :: p d2 -> p d1
default equals :: p d1 -> p d1
equals = id
data Dict k (m :: * -> *) where Dict :: k m => Dict k m
type Constraint d a = forall m. d m -> m a
data (d1 :+: d2) (m :: * -> *) = Plus (d1 m) (d2 m)
newtype ConstraintTrans d = ConstraintTrans {runCT :: Constraint d () -> Constraint d ()}
warmAndFuzzy ::
forall r d.
Equals d (Dict (MonadCo r) :+: Dict (MonadReader Int)) =>
Constraint d () -> Constraint d ()
warmAndFuzzy =
let scary' ::
(MonadCo r m, MonadReader Int m)
=> (forall m'. (MonadCo r m', MonadReader Int m') => m' ())
-> m ()
scary' = scary
waf :: Constraint (Dict (MonadCo r) :+: Dict (MonadReader Int)) () ->
Constraint (Dict (MonadCo r) :+: Dict (MonadReader Int)) ()
waf c (Plus Dict Dict) =
let arg :: forall m'. (MonadCo r m', MonadReader Int m') => m' ()
arg = c $ Plus Dict Dict
in scary' arg
in runCT $ equals $ ConstraintTrans waf
这应该是一个好的开始:
type ReaderAndCo r m = (MonadCo r m, MonadReader Int m)
g :: (forall m . Dict (ReaderAndCo r m) -> m ())
-> (forall m . Dict (ReaderAndCo r m) -> m ())
g x Dict = f (x Dict)
如果您愿意,可以进一步将ReaderAndCo
的字典ReaderAndCo
为两个组件。
为了使其更类似于您问题中的代码,您可以引入一个额外的同义词:
type Constrain k a = forall m . Dict (k m) -> m a
g :: Constrain (ReaderAndCo r) () -> Constrain (ReaderAndCo r) ()
g x Dict = f (x Dict)
这是你想要达到的目标吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.