2011-08-04 73 views
22

是否可以在函數的類型變量上放置一個不等式約束,如中的la foo :: (a ~ b) => a -> b,除了不等式而不是等式之外呢?是否可以將不等式約束放在haskell類型變量上?

我意識到有可能沒有直接的方法來做到這一點(因爲ghc文檔沒有列出任何我所知道的),但是如果根據所有這些不可能的話我會感到困惑我曾經接觸過的異國情調。

+8

對於哪個用例,您認爲不等式約束是否有用? – fuz

+1

具體而言,我試圖模擬數量的商品,即帶有標籤的數字,例如,使您能夠表達10個蘋果和2個梨的概念,並且如果您想添加梨和蘋果,則會引發類型錯誤。這本身就夠簡單了。然而,當我試圖用另一種商品來定義一種商品的價格時,每個梨子2個蘋果..當然,如果所銷售的商品類型與所購商品的類型不同,那麼價格纔有意義。(至少在我的頭上)。 所以,出於好奇,我只是想知道它是否實際上可以表達這個:) – plc

+1

我的懷疑是,雖然它可能是*愚蠢的*,價格是明確的(明顯是1),所以它是可能不值得嘗試對類型進行靜態要求的麻煩。 –

回答

24

首先,請記住,不同類型的變量都已經在其範圍內的非unifiable - e.g,如果你有\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'8。 我正在使用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

我試圖使用這種技術來消除重疊類型實例,但似乎無法讓它工作。見http://stackoverflow.com/questions/38549174/error-while-trying-to-use-type-families-to-dissambiguate-overlapping-instances-w – Jules

相關問題