Primero, tenga en cuenta que las distintas variables de tipo ya no son unifilables dentro de su alcance; por ejemplo, si tiene \x y -> x
, dándole el tipo de firma a -> b -> c
producirá un error acerca de no poder hacer coincidir las variables de tipo rígidas. De modo que esto solo se aplicaría a cualquier cosa que llame a la función, evitando que use una función polimórfica que de otro modo sería sencilla de manera que dos tipos sean iguales. Que funcionaría algo así, supongo:
const' :: (a ~/~ b) => a -> b -> a
const' x _ = x
foo :: Bool
foo = const' True False -- this would be a type error
Personalmente dudo que esto sería realmente útil - la independencia de las variables de tipo ya impide funciones genéricas se colapse a algo trivial, sabiendo dos tipos son desiguales no De hecho, te permite hacer algo interesante (a diferencia de la igualdad, que te permite coaccionar entre los dos tipos), y ser declarativo en lugar de condicional significa que no podrías usarlo para distinguir entre igual/desigual como parte de algún tipo de técnica de especialización .
Por lo tanto, si tiene en mente un uso específico en donde desea esto, le sugiero que pruebe un enfoque diferente.
Por otro lado, si lo que desea es jugar con ridícula tipo hackery ...
{-# 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
Bueno, eso fue increíblemente tonta. Funciona, sin embargo:
> const' True()
True
> const' True False
<interactive>:0:1:
Couldn't match type `No' with `Yes'
(...)
¿Para qué caso de uso, cree que sería útil una restricción de desigualdad? – fuz
Específicamente, intento modelar cantidades de productos, es decir, números con una etiqueta, por ejemplo, lo que le permite expresar la noción de tener 10 manzanas y 2 peras, y provocar un error de tipo si desea agregar peras y manzanas. Eso en sí mismo es bastante simple. Donde me quedé corto, sin embargo, es cuando intento definir un precio de un bien en términos de otro, p. 2 manzanas por pera ... Naturalmente, un precio solo tiene sentido si el tipo de productos que se venden es diferente del tipo de productos que se compran ... (Al menos en mi cabeza). Así que, por curiosidad, me preguntaba si era posible expresar esto :) – plc
Mi sospecha es que, aunque puede ser * tonto *, el precio está bien definido (1 por 1, obviamente), así que es probablemente no valga la molestia de tratar de poner un requisito estático sobre los tipos que son diferentes. –