2017-04-27 46 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)