背景:我不理解~并且正在请求用例。
假设:
{-# 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
在什么情况下才有用?
答案 0 :(得分: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)