2011-08-04 3 views
22

함수의 형식 변수에 부등식 제약 조건을 적용 할 수 있습니까? foo :: (a ~ b) => a -> bGHC type family docs 같이 같음이 아닌 다른 수식 제외?haskell 유형 변수에 부등식 제약 조건을 둘 수 있습니까?

ghc 문서가 내 지식을 나열하지 않기 때문에 가능한 직접적인 방법이 없다는 것을 알고 있습니다. 그러나 이것이 모든면에서 가능하지 않다면 나는 거의 당황 할 것입니다. 나는 이국적인 타입 - fu에 노출되었다.

+8

어떤 불균형 제약이 유용 할 것이라고 생각하십니까? – fuz

+1

특히, 상품 수량, 즉 태그가있는 숫자를 모델링하려고합니다. 예를 들어 10 개의 사과와 2 개의 배가있는 개념을 표현하고 배와 사과를 추가하려면 유형 오류를 유발할 수 있습니다. 그 자체로는 충분히 간단합니다. 그러나 내가 짧아 졌을 때, 한 상품의 가격을 다른 상품의 가격으로 정의하려고 할 때입니다. 배당 사과 2 개 .. 당연히 판매되는 제품의 유형이 구매되는 상품의 유형과 다른 경우에만 가격이 적합합니다. (적어도 내 머리 속에). 그래서, 호기심에서 나는 이것을 실제로 표현할 수 있는지 궁금해했습니다. – plc

+1

의심 할 여지가 있지만 어리석은 *일지도 모르지만 가격은 잘 정의되어 있습니다 (분명히 1에 1). 그래서 아마도 다른 유형의 정적 요구 사항을 넣으려는 번거 로움을 감당할 가치가 없을 것입니다. –

답변

24

우선, 고유 한 유형 변수가 해당 범위 내에서 이미 통합 할 수 없음을 기억하십시오. 예를 들어, \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' 
    (...) 
+0

매우 정교한 대답을 해줘서 고맙습니다. - 호기심을 만족시키기위한 것입니다 .-). 그리고 내 질문에 동기를 부여하지 않아서 유감스럽게 생각합니다. - 질문에 대한 의견으로 내 마음을 정교하게했습니다 :-) – plc

+0

참고 독자들에게 : 클래스 함수 ('typeEq','maybeCast' 등)는 예제와 무관하며 무시되거나 삭제 될 수 있습니다. – ntc2

+0

이것이 제대로 작동합니까? 'const 'True()가 정상적으로 작동하는 것처럼 보일 때'const'2()'는'const ''a'뿐만 아니라 오류를 반환합니다. ghc 7.4.1 – tohava

6

GHC 7.8.1. closed type families are available. 해결책은 그 (것)들로 매우 더 간단하다 :

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 
+0

이 기술을 사용하여 겹쳐진 typeclass 인스턴스를 모호하게 만들려고 시도했지만 작동하지 않는 것처럼 보입니다. http://stackoverflow.com/questions/38549174/error-while-trying-to-use-type-families-to-dissambiguate-overlapping-instances-w를 참조하십시오. – Jules

관련 문제