2016-07-27 13 views
18

कर सकते हैं मैं, और यदि ऐसा है तो, मैं कैसे एक समारोह के लिए प्रकार हस्ताक्षर लिख सकता हूँ:प्रकार हस्ताक्षर

g f x y = (f x, f y) 

इस तरह की है कि दिया:

f1 :: a -> [a] 
f1 x = [x] 

x1 :: Int 
x1 = 42 

c1 :: Char 
c1 = 'c' 

f2 :: Int -> Int 
f2 x = 3 * x 

x2 :: Int 
x2 = 5 

इस तरह की है कि :

g f1 x1 c1 == ([42], ['c']) :: ([Int], [Char]) 
g f2 x1 x2 == (126, 15) :: (Int, Int) 
+1

@ErikR के रूप में आपको दिखाया गया है कि अब (अब हटाया गया) जवाब बाएं हाथ की तरफ काम करने योग्य है लेकिन rhs पर प्रकार 'f' के प्रकार पर निर्भर करता है, इसलिए मुझे लगता है कि आपको टाइप-परिवारों का भी उपयोग करना होगा - यदि यह आपके लिए सही है, तो यह संभव है - निश्चित रूप से यह केवल एक अनुमान है - क्योंकि मुझे पता है कि इसे व्यक्त करने का एक तरीका है;) – Carsten

+0

जीएचसी एक्सटेंशन का उपयोग करने में खुशी – Clinton

+0

@ user3237465: एक त्वरित नज़र में (कम से कम आपका सरल संस्करण) मुझे लगता है कि आप 'f2' के साथ परेशानी में भाग लेंगे क्योंकि यह * * के लिए * नहीं है, लेकिन केवल' Int' के लिए – Carsten

उत्तर

15

नहीं, आप नहीं कर सकते। मूल समस्या यह है कि हास्केल के वाक्यविन्यास ने आपको यह सोचने में मूर्ख बना दिया है कि f1 और f2 के प्रकार वास्तव में उनके समान हैं। एक बार जब GHC कोर में अनुवाद किया, बल्कि वे अधिक अलग दिख:

f1 :: forall a . a -> [a] 
f2 :: Int -> Int 

केवल यही नहीं, लेकिन शर्तों बल्कि विभिन्न नज़र इसी:

f1 = Λa -> λ(x :: a) -> [x] 
f2 = λ(x :: Int) -> 3 * x 

आप देख सकते हैं, f1 और f2 वास्तव में है तर्कों की विभिन्न संख्या, जहां f1टाइप और मान औरलेता हैसिर्फ एक मूल्य लेता है।

अधिक सामान्य परिस्थितियों में, जब आप एक संदर्भ प्रकार, कहते हैं, Int -> [Int] के एक समारोह की उम्मीद में f2 खटखटाने, GHC आवश्यक प्रकार के f2 लागू होगी आप (यानी, एक विशिष्ट प्रकार के f2 का दृष्टांत) के लिए, और सभी इच्छा खुश रहो। उदाहरण के लिए, यदि आप

g :: (Int -> [Int]) -> Bool 

है और आप f को g लागू होते हैं, GHC वास्तव में उस

g (f @Int) 

को संकलित कर देगा लेकिन यहाँ आप पर है कि इन्स्टेन्शियशन होता है या नहीं, जो GHC नहीं करता है 'कि क्या बहुरूपता चाहते टी समर्थन (मुझे लगता है कि यह कोर भाषा में बल्कि एक कट्टरपंथी और विनाशकारी परिवर्तन होगा)।

कक्षा के उदाहरणों के बाद, परिवार के पैटर्न टाइप करें, और परिवार के परिणामों को टाइप करें, मुझे प्रमाणित नहीं किया जा सकता है, मुझे पूरा भरोसा है कि आप जो चाहते हैं उसे पाने के लिए कोई रास्ता नहीं है।

7

यदि आप my answer to a similar question here पर भिन्नता का उपयोग करके Proxy तर्क जोड़ना चाहते हैं तो यह वास्तव में संभव है।

है कि इसका जवाब से मेरे स्पष्टीकरण के अधिकांश यहाँ रखती है, लेकिन हम थोड़ा कुछ और सहायक प्रकार वर्गों (मैं क्या List और Both यहाँ फोन कर रहा हूँ) जोड़कर उस पर विस्तार करने के लिए की जरूरत है:

{-# LANGUAGE RankNTypes   #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeFamilies   #-} 
{-# LANGUAGE FlexibleInstances  #-} 
{-# LANGUAGE ConstraintKinds  #-} 

import   Data.Proxy 

f1 :: a -> [a] 
f1 x = [x] 

x1 :: Int 
x1 = 42 

c1 :: Char 
c1 = 'c' 

f2 :: Int -> Int 
f2 x = 3 * x 

x2 :: Int 
x2 = 5 

class b ~ [a] => List a b 
instance List a [a] 

class (a ~ b, b ~ c) => Both a b c 
instance Both a a a 

g :: (c a r1, c b r2) => 
     Proxy c -> (forall x r. c x r => x -> r) -> a -> b -> (r1, r2) 
g _ f x y = (f x, f y) 

यह हमें

ghci> g (Proxy :: Proxy List) f1 x1 c1 
([42],"c") 
ghci> g (Proxy :: Proxy (Both Int)) f2 x1 x2 
(126,15) 

List और Both कर की अनुमति देता है (विशेष रूप से List) सबसे अच्छा नाम नहीं हैं, ताकि आप बेहतर लोगों को अगर आप साथ आने के लिए चाहते हो सकता है घ o इसका उपयोग करें (हालांकि मुझे यकीन नहीं है कि मैं उत्पादन कोड में इस तरह के प्रकार की चालबाजी करने का सुझाव दूंगा, जब तक कि आपके पास वास्तव में अच्छा कारण न हो)।

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