簡體   English   中英

如何使用Data.Constraint來約束約束?

[英]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 rMonadReader 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM