简体   繁体   English

如何使用Data.Constraint来约束约束?

[英]How do I use Data.Constraint to reify constraints?

I have a function of type 我有类型的功能

(forall m. (MonadCo r m, MonadReader Int m) => m ())
    -> (forall m. (MonadCo r m, MonadReader Int m) => m ())

( MonadCo is my own typeclass representing a coroutine monad. If you like you could consider the case MonadError em instead. The question will be identical.) MonadCo是我自己的类角度代表一个协程monad。如果你喜欢你可以考虑MonadError em的情况。问题将是相同的。)

It seems like I should be able to reify the constraint and end up with a function with type signature like 看起来我应该能够重新定义约束并最终得到类型签名的函数

(Equals k (MonadCo r, MonadReader Int))
    => (Constrain k ()) -> (Constrain k ())

but I have no idea how to go about implementing this in practice. 但我不知道如何在实践中实现这一点。 I am completely baffled as to what :- and :=> actually are. 我对以下内容感到困惑:-:=>实际上是。 I suppose I also need a Forall1 in there somewhere, because I'm universally quantifying over m , but I don't see where it should fit. 我想我还需要一个Forall1在那里,因为我普遍量化m ,但我不知道它应该适合哪里。

Really what I want to do is reify the forall m. (MonadCo rm, MonadReader Int m) 真正想要做的就是重新实现这一目标forall m. (MonadCo rm, MonadReader Int m) forall m. (MonadCo rm, MonadReader Int m) constraint. forall m. (MonadCo rm, MonadReader Int m)约束。 I presume that when I do that, whatever ends up appearing on the left hand side will automatically be "the right thing". 我认为,当我这样做时,左边出现的任何结果都将自动成为“正确的东西”。

Data.Constraint seems very powerful, but I can't work out where to start. Data.Constraint似乎非常强大,但我无法找到从哪里开始。

Doesn't seem possible. 似乎不可能。 Looks like your "Implies" would be contravariant in k, while the function you want won't be. 看起来你的“Implies”在k中是逆变的,而你想要的功能则不会。

I mean, what if you have some bizarre class MonadFoo m , and you define 我的意思是,如果你有一些奇怪的MonadFoo m类,你会定义

type k m = (MonadCo r m, MonadReader Int m, MonadFoo m)

Suppose that this class is specifically designed in such a way that there could be only one instance of this class (well, if you don't use GeneralizedNewtypeDeriving at least), some monad MMM , which is also an instance of MonadCo r and MonadReader Int . 假设这个类是专门设计的,这个类只有一个实例(好吧,如果你不至少使用GeneralizedNewtypeDeriving ),一些monad MMM ,它也是MonadCo rMonadReader Int一个实例。 。 Then your type Constrain k () would likely be isomorphic to just MMM () . 然后你的类型Constrain k ()可能与MMM ()同构。 So, you want a function MMM () -> MMM () — but the input type, MMM () is so much weaker than what you need for your function to work. 所以,你想要一个函数MMM () -> MMM () - 但是输入类型MMM ()比你的函数工作所需要的要弱得多。 It's unlikely you'd be able to generalize your function in this way. 您不可能以这种方式概括您的功能。

UPDATE: 更新:

Some happy Oleg'ing, and we have the following code: 一些快乐的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

This should be a good start: 这应该是一个好的开始:

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)

You can further split the dictionary for ReaderAndCo into two components if you wish. 如果您愿意,可以进一步将ReaderAndCo的字典ReaderAndCo为两个组件。

To make it more similar to the code in your question, you can introduce an additional synonym: 为了使其更类似于您问题中的代码,您可以引入一个额外的同义词:

type Constrain k a = forall m . Dict (k m) -> m a

g :: Constrain (ReaderAndCo r) () -> Constrain (ReaderAndCo r) ()
g x Dict = f (x Dict)

Is this what you wanted to achieve? 这是你想要达到的目标吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM