2017-04-27 23 views
5

背景:我不明白~並正在請求一個用例。使用2函數理解`〜`

考慮:

{-# LANGUAGE GADTs #-} 

f :: a ~ b => a -> b -> b 
f a b = a 

g :: a -> a -> a 
g a b = a 

在我看來,這兩個功能都是平等的:

Prelude> :r 
[1 of 1] Compiling Main    (TypeEq.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> f 10 20 
10 
*Main> g 10 20 
10 

在什麼情況下會是使用f超過g有用嗎?

+4

的確,沒有優勢在這種情況下:這些功能是平等的。我想你需要類似家庭或GADT的東西來看看一些有用的東西。或者$ Data.Typeable.eqT $可以作爲一個很好的例子。 – chi

+3

如果你想知道如何以一種非常有用的方式使用'〜',請閱讀Chris Done這篇偉大的博客文章:http://chrisdone.com/posts/haskell-constraint-trick – Shersh

回答

9
{-# LANGUAGE TypeFamilies #-} 

import GHC.Exts (IsList(..)) 

fizzbuzz :: (IsList l, Item l ~ Int) => l -> IO() 
fizzbuzz = go . toList 
where go [] = return() 
     go (n:m) 
     | n`mod`3==0 = putStrLn "fizz" >> go m 
     | n`mod`5==0 = putStrLn "buzz" >> go m 
     | otherwise = print n >> go m 

然後

Prelude> fizzbuzz [1..7] 
1 
2 
fizz 
4 
buzz 
fizz 
7 
Prelude> import Data.Vector.Unboxed as UA 
Prelude UA> fizzbuzz (UA.fromList[1..7] :: UA.Vector Int) 
1 
2 
fizz 
4 
buzz 
fizz 
7 

您現在可以反對,這應該更好地已經完成了Foldable約束,而不是醜陋的轉換到一個列表。實際上,這是無法完成的,因爲由於Unbox約束,無盒裝矢量沒有可摺疊的實例!

這可能,但是,正如以及已經完成了非均分約束,即

fizzbuzz :: (IsList l, Num (Item l), Eq (Item l), Show (Item l)) 
    => l -> IO() 

較籠統,但可以說也比較尷尬。當你需要時,在實踐中,無論如何,只有一個包含類型,一個等式約束可能是一個不錯的選擇。

事實上,我有時覺得方便在等式約束折騰只是爲了讓一個類型簽名更簡潔,如果它是一個有點重複:簽名

complicatedFunction :: Long (Awkward (Type a) (Maybe String)) 
       -> [Long (Awkward (Type a) (Maybe String))] 
       -> Either String (Long (Awkward (Type a) (Maybe String))) 

可以

complicatedFunction :: r ~ Long (Awkward (Type a) (Maybe String)) 
      => r -> [r] -> Either String r 
被替換

這可能比其他DRY可能性更好

type LAwkTS a = Long (Awkward (Type a) (Maybe String)) 

complicatedFunction :: LAwkTS a -> [LAwkTS a] -> Either String (LAwkTS a)