简体   繁体   English

约束蕴涵作为约束

[英]Constraint implication as a constraint

How can I encode a constraint implication in Haskell into a new constraint?如何将 Haskell 中的约束蕴涵编码为新约束? In my example, I want to require that every Functor cdf needs to be such that Obj cx implies Obj c (fx) .在我的例子中,我想要求每个Functor cdf需要Obj cx暗示Obj c (fx) I am writing the constraint forall x . Obj cx => Obj d (fx)我正在为所有forall x . Obj cx => Obj d (fx)编写约束forall x . Obj cx => Obj d (fx) forall x . Obj cx => Obj d (fx) . forall x . Obj cx => Obj d (fx)

{-# LANGUAGE AllowAmbiguousTypes       #-}
{-# LANGUAGE KindSignatures            #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE RankNTypes                #-}
{-# LANGUAGE ScopedTypeVariables       #-}
{-# LANGUAGE TypeApplications          #-}
{-# LANGUAGE TypeFamilies              #-}
{-# LANGUAGE QuantifiedConstraints     #-}

import Prelude hiding (id, Functor, fmap)
import Data.Kind

class Category c where                            
  type Obj c a :: Constraint                    
  id :: (Obj c x) => c x x                        
  comp :: (Obj c x) => c y z -> c x y -> c x z    

class ( Category c, Category d, forall x . Obj c x => Obj d (f x))
      => Functor c d f where
  fmap :: (Obj c x, Obj c y) => c x y -> d (f x) (f y)

doublefmap :: forall c f x . (Category c , Functor c c f, Obj c x)
           => c x x -> c (f (f x)) (f (f x))
doublefmap = fmap @c @c @f . fmap @c @c @f

But this produces the following error:但这会产生以下错误:

Minimal.hs:27:14: error:
    • Could not deduce: Obj c (f x) arising from a use of ‘fmap’
      from the context: (Functor c c f, Obj c x)
        bound by the type signature for:
                   doublefmap :: forall (c :: * -> * -> *) (f :: * -> *) x.
                                 (Category c, Functor c c f, Obj c x) =>
                                 c x x -> c (f (f x)) (f (f x))
        at Minimal.hs:(25,1)-(26,44)
    • In the first argument of ‘(.)’, namely ‘fmap @c @c @f’
      In the expression: fmap @c @c @f . fmap @c @c @f
      In an equation for ‘doublefmap’:
          doublefmap = fmap @c @c @f . fmap @c @c @f
    • Relevant bindings include
        doublefmap :: c x x -> c (f (f x)) (f (f x))
          (bound at Minimal.hs:27:1)

What am I doing wrong here?我在这里做错了什么? What additional hints should I give the compiler?我应该给编译器什么额外的提示? Is there any better way of achieving this?有没有更好的方法来实现这一目标?

My guess is that I would need to use Data.Constraint and :- , but how?我的猜测是我需要使用Data.Constraint:- ,但是如何使用?

The following seems to work, but I do not know if this is an easier way.以下似乎有效,但我不知道这是否更简单。 It uses the operator (\\\\) from Data.Constraint .它使用来自Data.Constraint的运算符(\\\\)

{-# LANGUAGE AllowAmbiguousTypes       #-}
{-# LANGUAGE KindSignatures            #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE RankNTypes                #-}
{-# LANGUAGE ScopedTypeVariables       #-}
{-# LANGUAGE TypeApplications          #-}
{-# LANGUAGE TypeFamilies              #-}
{-# LANGUAGE TypeOperators             #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE QuantifiedConstraints     #-}

import Prelude hiding (id, Functor, fmap)
import Data.Constraint

class Category c where                            
  type Obj c a :: Constraint
  id :: (Obj c x) => c x x
  comp :: (Obj c x) => c y z -> c x y -> c x z    

class (Category c, Category d) => Functor c d f where
  fobj :: forall x. Obj c x :- Obj c (f x)
  fmap :: (Obj c x, Obj c y) => c x y -> d (f x) (f y)

doublefmap :: forall c f x . (Category c , Functor c c f, Obj c x)
           => c x x -> c (f (f x)) (f (f x))
doublefmap = (fmap @c @c @f . fmap @c @c @f) \\ fobj @c @c @f @x

This is a second solution without using Data.Constraint that (at least to me) seems a bit more elegant.这是不使用Data.Constraint的第二种解决方案(至少对我而言)似乎更优雅一些。

{-# LANGUAGE AllowAmbiguousTypes           #-}
{-# LANGUAGE KindSignatures            #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE RankNTypes                #-}
{-# LANGUAGE ScopedTypeVariables       #-}
{-# LANGUAGE TypeApplications          #-}
{-# LANGUAGE TypeFamilies              #-}
{-# LANGUAGE TypeOperators              #-}
{-# LANGUAGE FlexibleContexts              #-}
{-# LANGUAGE QuantifiedConstraints      #-}
{-# LANGUAGE ConstraintKinds           #-}

import Prelude hiding (id, Functor, fmap)

class Category objc c where                            
  id :: (objc x) => c x x
  comp :: (objc x) => c y z -> c x y -> c x z

class (Category objc c, Category objd d, forall x . (objc x) => objd (f x))
      => Functor objc c objd d f where
  fmap :: (objc x, objc y) => c x y -> d (f x) (f y)

doublefmap :: forall c f x objc objd . (Category objc c , Functor objc c objc c f, objc x)
           => c x x -> c (f (f x)) (f (f x))
doublefmap = (fmap @objc @c @objc @c @f . fmap @objc @c @objc @c @f) 

I would be happy if someone can improve this.如果有人可以改进这一点,我会很高兴。

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

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