Как поставить ограничения на переменную типа вида "Constraint"?

я играю с

2 ответов


самое близкое, что мы можем получить, это Class1 класс, reifys отношения между классом и одно ограничение суперкласса, как класс. Он основан на Class С ограничения.

во-первых, мы возьмем короткий тур пакета ограничений. А Dict захватывает словарь для Constraint

data Dict :: Constraint -> * where
  Dict :: a => Dict a

:- захватывает, что одно ограничение влечет за собой другой. Если у нас есть a :- b, всякий раз, когда у нас есть ограничение a мы можем создать словарь для ограничения b.

newtype a :- b = Sub (a => Dict b)

нам нужно доказательство, подобное :-, мы должны знать, что forall a. h a :- b a или h a => Dict (b a).

Одиночное Наследование

фактически реализуя это для classes только с одним наследованием требует кухонной раковины языковых расширений, в том числе OverlappingInstances.

{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}

import Data.Constraint

определим класс ограничений добрый k -> Constraint где ограничение имеет один суперкласс.

class Class1 b h | h -> b where
    cls1 :: h a :- b a

теперь мы оснащены для решения нашей проблемы примера. У нас есть класс A требует Show экземпляра.

 class Show a => A a
 instance A Int

Show - это суперкласс A

instance Class1 Show A where
    cls1 = Sub Dict 

мы хотим написать Show экземпляров Some

data Some (c :: * -> Constraint) where
    Some :: c a => a -> Some c

у нас можете Show a Some Show.

instance Show (Some Show) where
    showsPrec x (Some a) = showsPrec x a

у нас можете Show a Some h, когда h есть один суперкласс!--17--> и мы могли бы показать Some b.

instance (Show (Some b), Class1 b h) => Show (Some h) where
    showsPrec x (Some (a :: a)) = 
        case cls1 :: h a :- b a of
            Sub Dict -> showsPrec x ((Some a) :: Some b)

это позволяет нам писать

x :: Some A
x = Some (1 :: Int)

main = print x

вы не можете сделать Some c экземпляр Show, кроме тривиально.

вы хотите show на a внутри Some, но эта переменная экзистенциально количественная, поэтому мы не можем зависеть от каких-либо знаний типа a. В частности, мы не можем знать, что a пример Show.

EDIT: я расширю свой ответ. Даже с большим количеством машин и отказавшись от Show например, я все еще не думаю то, что вы хотите, возможно из-за экзистенциальной квантификации.

сначала я перепишу Some в более знакомой форме

data Dict p where
    Dict :: p a => a -> Dict p

обычный способ говорить о" ограничениях, подразумевающих ограничения", - это концепция ограничения.

data p :- q where
    Sub :: p a => Dict q -> p :- q

мы можем думать о значение типа p :- q как доказательство того, что если ограничение forall a. p a, то forall a. q a следующий.

теперь попробуем написать толковое show-ишь функция

showD :: p :- Show -> Dict p -> String
showD (Sub (Dict a)) (Dict b) = show b

на первый взгляд, это может сработать. Мы ввели в область действия следующие ограничения (простите псевдо -exists синтаксис)

(0) p :: * -> Constraint
(1) exists a. p a           -- (Dict p)
(2) exists b. p b => Show b -- (p :- Show)

но теперь все разваливается, GHC справедливо жалуется:

main.hs:10:33:
    Could not deduce (Show a2) arising from a use of `show' 
    from the context (p a)
      bound by a pattern with constructor
                 Sub :: forall (p :: * -> Constraint) (q :: * -> Constraint) a.
                        (p a) => 
                        Dict q -> p :- q,
               in an equation for `showD' 
      at main.hs:10:8-19                    
    or from (Show a1) 
      bound by a pattern with constructor
                 Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p, 
               in an equation for `showD'
      at main.hs:10:13-18 
    or from (p a2)
      bound by a pattern with constructor
                 Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
               in an equation for `showD'
      at main.hs:10:23-28   

потому что невозможно унифицировать a С (1) С b С (2).

это та же самая существенная идея, которая используется во всем constraints пакета, указанного в комментарии.