2009-12-01 10 views
7

ちょっと役に立ってちょっと役に立ちましたon - 機能ができます。Haskellに正しい多型を計算させる方法は?

例:

orderByLength = sortBy (compare `on` length) 

しかし残念ながら、推論された型は、いくぶん直感に反することができます。一つは、例えば可能性が

非常定義によれば

f `on` g = \x y -> f (g x) (g y) 

\x y -> (length x) == (length y) 

しかし、両者が異なる種類を持っていると

(==) `on` length 

置き換えます!

最初の文字は[a] -> [a] -> Boolですが、2番目の文字は正しい、より一般的なタイプの[a] -> [b] -> Boolです。

これは、(on (==) length) [1, 2, 3] ["a", "b", "c"](これはTrueとなるはずですが、タイプチェックにも失敗するはずです)のような明らかに正しい用語を許可しません。

私はこの制限がfirst-rank typesの使用により発生することを知っていますが、これを克服する方法はありますか?多人数関数を正しく扱うことができるonの実装を定式化することはできますか(普遍的な数値化/ランクn型を使用して)?一方

 
Prelude> :t on' (==) 
on' (==) :: (Eq a) => (forall d. c d -> a) -> c e -> c f -> Bool 
Prelude> :t on' (==) length 
on' (==) length :: [e] -> [f] -> Bool 

答えて

3
{-# LANGUAGE Rank2Types #-} 
on' :: (a -> a -> b) -> (forall d. c d -> a) -> c e -> c f -> b 
on' f g x y = f (g x) (g y) 

この結果は、この署名もなりflip on' id望ましいより幾分少ないである、違法。


{-# LANGUAGE TemplateHaskell #-} 
import Language.Haskell.TH 
onE f g = do 
    x <- newName "x" 
    y <- newName "y" 
    lamE [varP x, varP y] $ f `appE` (g `appE` varE x) `appE` (g `appE` varE y) 
 
Prelude> :set -XTemplateHaskell 
Prelude> $(onE [|(==)|] [|length|]) [1,2,3] ["a","b","c"] 
True 
Prelude> $(onE [|(==)|] [|id|]) 4 5 
False 
+0

クールなもの - 'C'とは何ですか?一種の '* - > *'?ああ、それは ''型 ''の潜在的な使用を包むことです...あなたは* kind *のためにそれを一般化できますか? – Dario

+0

両方のアイデアのためにクール、ありがとう – Dario

関連する問題