2009-12-01 7 views
7

मुझे अभी एहसास हुआ कि on -फंक्शन कितना उपयोगी हो सकता है।हास्केल को सही पॉलीमोर्फिक प्रकार की गणना कैसे करें?

पूर्व:

orderByLength = sortBy (compare `on` length) 

लेकिन दुर्भाग्य से, अनुमानित प्रकार कुछ हद तक जवाबी सहज ज्ञान युक्त हो सकता है।

बहुत परिभाषा

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

एक जैसे सकता है के अनुसार

(==) `on` length 

की जगह

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

लेकिन दोनों विभिन्न प्रकार के साथ!

पहले में [a] -> [a] -> Bool है जबकि दूसरे में सही, अधिक सामान्य प्रकार [a] -> [b] -> Bool है।

यह स्पष्ट रूप से (on (==) length) [1, 2, 3] ["a", "b", "c"] जैसे सही शब्दों को अस्वीकार करता है (जो True उत्पन्न करना चाहिए लेकिन अब भी टाइप-चेकिंग में विफल रहता है)।

मुझे पता है कि first-rank types के उपयोग के कारण यह प्रतिबंध आता है, लेकिन इसे कैसे दूर किया जाए? क्या कोई on के कार्यान्वयन को तैयार कर सकता है जो पॉलिमॉर्फिक कार्यों (सार्वभौमिक मात्रा/रैंक-एन प्रकारों का उपयोग करके) के साथ सही ढंग से सौदा कर सकता है? दूसरी ओर

 
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' क्या है? एक प्रकार '* -> *'? आह, यह '[प्रकार] 'के संभावित उपयोग को लपेटना है ... क्या आप इसे किसी भी * प्रकार * के लिए सामान्यीकृत कर सकते हैं? – Dario

+0

कूल, दोनों विचारों के लिए धन्यवाद – Dario