2010-01-28 13 views
14

this article on writing polyvariadic functions in Haskell पढ़ने के बाद, मैंने अपना कुछ लिखने की कोशिश की।हास्केल में पॉलीवायरैडिक फ़ंक्शन

पहले मैंने सोचा कि मैं इसे सामान्यीकृत करने का प्रयास करूंगा - इसलिए मेरे पास एक ऐसा कार्य हो सकता है जो दिए गए तर्कों को ध्वस्त करके विविध कार्य करता है।

{-# OPTIONS -fglasgow-exts #-} 
module Collapse where 
class Collapse a r | r -> a where 
    collapse :: (a -> a -> a) -> a -> r 
instance Collapse a a where 
    collapse _ = id 
instance (Collapse a r) => Collapse a (a -> r) where 
    collapse f a a' = collapse f (f a a') 

हालांकि, संकलक कि पसंद नहीं आया:

Collapse.hs:5:9: 
    Functional dependencies conflict between instance declarations: 
     instance Collapse a a -- Defined at Collapse.hs:5:9-20 
     instance (Collapse a r) => Collapse a (a -> r) 
     -- Defined at Collapse.hs:7:9-43 

अगर मैं वापस चला गया और अंतिम परिणाम के लिए एक आवरण प्रकार जोड़ा, तथापि, यह काम किया:

module Collapse where 
class Collapse a r | r -> a where 
    collapse :: (a -> a -> a) -> a -> r 
data C a = C a 
instance Collapse a (C a) where 
    collapse _ = C . id 
instance (Collapse a r) => Collapse a (a -> r) where 
    collapse f a a' = collapse f (f a a') 
sum :: (Num a, Collapse a r) => a -> r 
sum = collapse (+) 

एक बार मैंने यह परिवर्तन करने के बाद, यह ठीक संकलित किया, और ghci में collapse फ़ंक्शन का उपयोग कर सकता था।

ghci> let C s = Collapse.sum 1 2 3 in s 
6 

मुझे यकीन नहीं है कि अंतिम परिणाम के लिए रैपर प्रकार की आवश्यकता क्यों है। अगर कोई इसे समझा सकता है, तो मैं इसकी सराहना करता हूं। मैं देख सकता हूं कि संकलक मुझे बता रहा है कि यह कार्यात्मक निर्भरताओं के साथ कुछ मुद्दा है, लेकिन मैं वास्तव में अभी तक धनपोतों का उचित उपयोग नहीं करता हूं।

बाद में, मैंने एक अलग टक लेने की कोशिश की, और एक सूची लेने वाले कार्यों के लिए एक वैरैडिक फ़ंक्शन जेनरेटर को आजमाएं और परिभाषित करें और एक मान वापस कर दिया। मुझे एक ही कंटेनर चाल करना था, और UndecidableInstances भी अनुमति देना था।

{-# OPTIONS -fglasgow-exts #-} 
{-# LANGUAGE UndecidableInstances #-} 
module Variadic where 
class Variadic a b r | r -> a, r -> b where 
    variadic :: ([a] -> b) -> r 
data V a = V a 
instance Variadic a b (V b) where 
    variadic f = V $ f [] 
instance (Variadic a b r) => Variadic a b (a -> r) where 
    variadic f a = variadic (f . (a:)) 
list :: Variadic a [a] r => r 
list = variadic . id 
foldl :: (Variadic b a r) => (a -> b -> a) -> a -> r 
foldl f a = variadic (Prelude.foldl f a) 

UndecidableInstances की अनुमति के बिना संकलक शिकायत की कि मेरी उदाहरण घोषणाओं अवैध थे:

ghci> let V l = Variadic.list 1 2 3 in l 
[1,2,3] 
ghci> let vall p = Variadic.foldl (\b a -> b && (p a)) True 
ghci> :t vall 
vall :: (Variadic b Bool r) => (b -> Bool) -> r 
ghci> let V b = vall (>0) 1 2 3 in b 
True 

मुझे लगता है:

Variadic.hs:7:0: 
    Illegal instance declaration for `Variadic a b (V b)' 
     (the Coverage Condition fails for one of the functional dependencies; 
     Use -XUndecidableInstances to permit this) 
    In the instance declaration for `Variadic a b (V b)' 

Variadic.hs:9:0: 
    Illegal instance declaration for `Variadic a b (a -> r)' 
     (the Coverage Condition fails for one of the functional dependencies; 
     Use -XUndecidableInstances to permit this) 
    In the instance declaration for `Variadic a b (a -> r)' 

हालांकि, एक बार यह संकलित, मैं इसे सफलतापूर्वक GHCi में इस्तेमाल कर सकते हैं जो मैं खोज रहा हूं वह एक स्पष्टीकरण है कि अंतिम मूल्य के लिए कंटेनर प्रकार क्यों आवश्यक है, साथ ही साथ सभी विभिन्न Functio नल निर्भरता आवश्यक हैं

इसके अलावा, इस अजीब लग रहा था:

ghci> let vsum = Variadic.foldl (+) 0 

<interactive>:1:10: 
    Ambiguous type variables `a', `r' in the constraint: 
     `Variadic a a r' 
     arising from a use of `Variadic.foldl' at <interactive>:1:10-29 
    Probable fix: add a type signature that fixes these type variable(s) 

<interactive>:1:10: 
    Ambiguous type variable `a'in the constraint: 
     `Num a' arising from the literal `0' at <interactive>:1:29 
    Probable fix: add a type signature that fixes these type variable(s) 
ghci> let vsum' = Variadic.foldl (+) 
ghci> :t vsum' 
(Num a, Variadic a a r) => t -> a -> r 
ghci> :t vsum' 0 
(Num a, Variadic a a r) => a -> r 
ghci> let V s = vsum' 0 1 2 3 in s 
6 

मुझे लगता है कि नतीजों है अनुमान लगा रहा हूँ UndecidableInstances अनुमति देने से है, लेकिन मैं नहीं जानता कि, और मैं बेहतर समझने के लिए क्या हो रहा है करना चाहते हैं।

+0

यह कुछ बहुत ही अच्छा कोड है जिसके साथ आप प्रयोग कर रहे हैं! और ओलेग Kiselyov द्वारा यह लेख बहुत अच्छा है, यह पहली बार मुझे इसे पढ़ने के लिए पूरी तरह से उड़ा दिया और अभी भी उस प्रभाव है। :-) मैंने रैपर प्रकार की आवश्यकता के संबंध में एक उत्तर में एक शॉट लिया ... उम्मीद है कि यह मदद करता है। –

उत्तर

8

कार्यात्मक निर्भरता के पीछे विचार यह r -> a बिट का कहना है कि जैसे

class Collapse a r | r -> a where 
    ... 

एक घोषणा में कि a विशिष्ट r द्वारा निर्धारित किया जाता है। तो, आपके पास instance Collapse (a -> r) (a -> r) और instance Collapse a (a -> r) नहीं हो सकता है। ध्यान दें कि instance Collapse (a -> r) (a -> r) पूरी तस्वीर के लिए instance Collapse a a से निम्न है।

दूसरे शब्दों में, आपका कोड instance Collapse t t (प्रकार परिवर्तनीय का नाम निश्चित रूप से महत्वहीन है) और instance Collapse a (a -> r) स्थापित करने का प्रयास कर रहा है। यदि आप पहले उदाहरण घोषणा में t के लिए (a -> r) को प्रतिस्थापित करते हैं, तो आपको instance Collapse (a -> r) (a -> r) मिल जाता है।अब यह Collapse का दूसरा उदाहरण है जो (a -> r) के बराबर दूसरे प्रकार के पैरामीटर के साथ है कि आपके पास हो सकता है, क्योंकि कक्षा घोषणा का कहना है कि पहला प्रकार पैरामीटर दूसरे से deducible होना है। फिर भी आप instance a (a -> r) स्थापित करने का प्रयास करें, जो Collapse का दूसरा उदाहरण (a -> r) के साथ दूसरे प्रकार के पैरामीटर के साथ जोड़ देगा। इस प्रकार, जीएचसी शिकायत करता है।

+0

शानदार! इससे बहुत मदद मिलती है! – rampion

+0

बढ़िया! मदद करने के लिए खुश। :-) मुझे लगता है कि कैमकैन के जवाब बहुत जानकारीपूर्ण w.r.t. हैं। UndecidableInstances मुद्दा और "गैर-फ़ंक्शंस के लिए उदाहरण" आलेख का लिंक बहुत अच्छा है ... एक बहुत ही प्रबुद्ध SO सवाल, यह! –

4

Michał Marczyk धन और उदाहरण मिलान समस्या के बारे में बिल्कुल सही है, और रैपर प्रकार एक आसान फिक्स की तरह लगता है। दूसरी तरफ, यदि आप पहले से ही ओलेग की साइट पढ़ रहे हैं, तो आप deeper down the rabbit hole पर जाना पसंद कर सकते हैं और "किसी भी प्रकार के फ़ंक्शन नहीं" के लिए एक उदाहरण लिखने का प्रयास कर सकते हैं।

जहां तक ​​अनिश्चितताएं चलती हैं, कवरेज की स्थिति here का वर्णन किया गया है; यह स्पष्ट होना चाहिए कि आपके उदाहरण क्यों विफल हो जाते हैं। ध्यान दें कि "अनावश्यक" शब्द का अर्थ लगभग समान अर्थ में अनावश्यक है जैसा कि "हैल्टिंग समस्या अनावश्यक है" - यह कहना है कि आप जीएचसी को कोड को हल करने का प्रयास करने की कोशिश कर रहे हैं जो इसे अनंत लूप में भेज सकता है केवल आपके दावे पर आधारित है कि यह ठीक है। स्वच्छ विचारों को हैक करने के लिए यह मजेदार है, लेकिन जीएचसी के लिए मानव प्रथम-पास टाइप-चेकर होने की सहमति देना एक बोझ है जिसे मैं व्यक्तिगत रूप से थकाऊ महसूस करता हूं।

5

आप अभी भी इस के साथ प्रयोग कर रहे हैं, यहां एक समारोह से एक polyvariadic समारोह का निर्माण कर एक सूची लेने का एक उदाहरण है, या तो एक आवरण प्रकार या अनिर्णनीय उदाहरणों की आवश्यकता के बिना: इस दृष्टिकोण को

{-# LANGUAGE FlexibleContexts #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FunctionalDependencies #-} 

class Variadic a b r | r -> a where 
    variadic :: ([a] -> b) -> r 

instance Variadic a b (a -> b) where 
    variadic f x = f [x] 

instance (Variadic a b (a -> r)) => Variadic a b (a -> a -> r) where 
    variadic f x y = variadic (f . (x:)) y 

vList :: (Variadic a [a] r) => r 
vList = variadic id 

vFoldl :: (Variadic b a r) => (a -> b -> a) -> a -> r 
vFoldl f z = variadic (foldl f z) 

vConcat :: (Variadic [a] [a] r) => r 
vConcat = vFoldl (++) [] 

main = do 
    putStrLn $ vConcat "abc" "def" "ghi" "jkl" 
    putStrLn $ vList 'x' 'y' 'z' 
    if vFoldl (&&) True True True True then putStrLn "Yes" else putStrLn "No" 
    if vFoldl (&&) True True False True then putStrLn "Yes" else putStrLn "No" 

कमियां क्या वे प्रकार चेकर परिणाम के प्रकार का अनुमान लगाने में सक्षम होना चाहिए (या आपको इसे एनोटेट करना होगा), और यह पॉलिमॉर्फिक न्यूमेरिक स्थिरांक पर बुरी तरह विफल रहता है; आपके द्वारा उल्लिखित आलेख में दोनों समस्याओं के कारणों पर चर्चा की गई है। यह नहीं पता कि आपको वह सहायक मिलेगा, लेकिन मैं पहले polyvariadic कार्यों के साथ tinkering था और इस सवाल को याद किया।

संबंधित मुद्दे