Можно ли наложить ограничения на неравенство на переменные типа haskell? - PullRequest
24 голосов
/ 04 августа 2011

Можно ли наложить ограничение неравенства на переменные типа функции, например foo :: (a ~ b) => a -> b, как в Документы семейства типов GHC , кроме неравенства, а не равенства?что, возможно, нет прямого способа сделать это (поскольку ghc docs не перечисляет ничего, насколько мне известно), но я был бы почти озадачен, если бы это было каким-то образом невозможно в свете всех экзотических типов фубыли подвергнуты.

Ответы [ 2 ]

26 голосов
/ 04 августа 2011

Во-первых, имейте в виду, что различные переменные типа уже не различимы в своей области видимости - например, если у вас есть \x y -> x, присвоение ему сигнатуры типа a -> b -> c приведет к ошибке о невозможности соответствия жесткимПеременные типа.Таким образом, это применимо только к чему-либо, вызывающему функцию, не позволяя ей использовать в противном случае простую полиморфную функцию таким образом, чтобы два типа были равны.Это будет работать примерно так, я предполагаю:

const' :: (a ~/~ b) => a -> b -> a
const' x _ = x

foo :: Bool
foo = const' True False -- this would be a type error

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

Так что, если вы имеете в виду какое-то конкретное использование, где вы этого хотите, я бы предложил попробовать другой подход.

С другой стороны, если вы просто хотите игратьс нелепым хакерством типа ...

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}

-- The following code is my own hacked modifications to Oleg's original TypeEq. Note
-- that his TypeCast class is no longer needed, being basically equivalent to ~.

data Yes = Yes deriving (Show)
data No = No deriving (Show)

class (TypeEq x y No) => (:/~) x y
instance (TypeEq x y No) => (:/~) x y

class (TypeEq' () x y b) => TypeEq x y b where
    typeEq :: x -> y -> b
    maybeCast :: x -> Maybe y

instance (TypeEq' () x y b) => TypeEq x y b where
    typeEq x y = typeEq' () x y
    maybeCast x = maybeCast' () x

class TypeEq' q x y b | q x y -> b where
    typeEq' :: q -> x -> y -> b
    maybeCast' :: q -> x -> Maybe y

instance (b ~ Yes) => TypeEq' () x x b where
    typeEq' () _ _ = Yes
    maybeCast' _ x = Just x

instance (b ~ No) => TypeEq' q x y b where
    typeEq' _ _ _ = No
    maybeCast' _ _ = Nothing

const' :: (a :/~ b) => a -> b -> a
const' x _ = x

Ну, это было невероятно глупо.Работает, хотя:

> const' True ()
True
> const' True False

<interactive>:0:1:
    Couldn't match type `No' with `Yes'
    (...)
10 голосов
/ 04 августа 2014

от GHC 7.8.1. доступны семейства закрытого типа . С ними решение намного проще:

data True
data False

type family TypeEqF a b where
  TypeEqF a a = True
  TypeEqF a b = False

type TypeNeq a b = TypeEqF a b ~ False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...