2017-10-03 3 views
8

निम्नलिखित हास्केल कोड पर विचार करें।क्या पॉइंटफ्री फॉर्म में पैटर्न-मिलान वाले फ़ंक्शन लिखना संभव है?

data Keypress = Keypress Int Char 

getSeq :: Keypress -> [Char] 
getSeq (Keypress i c) = replicate i c 

वहाँ किसी भी तरह से pointfree रूप में getSeq लिखने के लिए है?

getSeq की परिभाषा तो इसका पैटर्न मैच के लिए इसी तरह यह किसी तरह currying या monads या कुछ का उपयोग करने के i और c पैरामीटर निर्दिष्ट करने से बचने के लिए हो सकता है लगता है कि है। हालांकि, pointfree.iogetSeq के लिए पॉइंट-फ्री आउटपुट को हल नहीं करता है, मुझे लगता है कि पैटर्न मिलान के कारण।

क्या यह संभव है?

उत्तर

16

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

उदाहरण के लिए, Bool के लिए catamorphism

bool :: a -> a -> Bool -> a 
bool x _ False = x 
bool _ y True = y 

है और Either के लिए यह

either :: (a -> c) -> (b -> c) -> Either a b -> c 
either f g (Left x) = f x 
either f g (Right x) = g x 

एक और अधिक उन्नत catamorphism सूचियों के लिए एक है, जो आप शायद पहले देखा है है: foldr!

foldr :: (a -> b -> b) -> b -> [a] -> b 
foldr f init [] = init 
foldr f init (x:xs) = f x (foldr f init xs) 

हम नहीं आमतौर पर इस तरह से (या कम से कम मैं नहीं) इसके बारे में सोचते हैं, लेकिन foldr एक catamorphism है: यह, पैटर्न मिलान संभालती है और आप के रूप में इतने लंबे समय के रिकर्सिवली आप के लिए सूची deconstructing [a] के दो निर्माताओं में पाया मूल्यों के लिए "संचालकों" प्रदान करते हैं:

  • ही एक मामला [] को संभालने के लिए, कोई तर्क बिल्कुल की जरूरत: बस प्रकार b
  • ही एक मामला (x:xs) संभाल करने के एक मूल्य। इस मामले में x का प्रतिनिधित्व करने वाला एक तर्क होता है, जो सूची का प्रमुख होता है, और एक तर्क जो पूंछ को फिर से फोल्ड करने के परिणाम का प्रतिनिधित्व करता है, b का मान।

एक catamorphism केवल एक निर्माता के साथ एक प्रकार के लिए कम रोमांचक है, लेकिन हम आसानी से अपने Keypress प्रकार के लिए एक परिभाषित कर सकते हैं:

key :: (Int -> Char -> a) -> Keypress -> a 
key f (Keypress x c) = f x c 

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

यह परिभाषित करने के बाद कि आम तौर पर एक बार उपयोगी काम होता है, आप अपने दिल की इच्छाओं के किसी भी बिंदु-मुक्त कार्य को लागू करने के लिए इसे कई बार उपयोग कर सकते हैं। आपके मामले में, आप बस

getSeq :: Keypress -> [Char] 
getSeq = key replicate 
लिख सकते हैं
5

आप इसे बॉयलरप्लेट के बिना कुछ नहीं कर सकते हैं, लेकिन lens आपके लिए उस बॉयलरप्लेट को उत्पन्न कर सकता है, तो संभवतः यह उतना करीब है जितना आप प्राप्त करने जा रहे हैं।

Control.Lens.TH से makePrisms का उपयोग करते हुए एक Iso है, जो है, अनिवार्य रूप से, एक एकल निर्माता डेटाप्रकार पर एक प्रथम श्रेणी पैटर्न मैचों उत्पन्न होगा। सुविधाजनक, Iso एस बिडरेक्शनल हैं, इसलिए आप view उन्हें (पैटर्न-मिलान जैसे मूल्यों को प्राप्त करने के लिए) और review उन्हें (सामान्य रूप से कन्स्ट्रक्टर का उपयोग करने जैसे मूल्य को वापस करने के लिए) कर सकते हैं।

makePrisms और view का उपयोग करना, यह एक pointfree तरह से getSeq लिखने के लिए संभव है:

{-# LANGUAGE TemplateHaskell #-} 
import Control.Lens 

data Keypress = Keypress Int Char 
makePrisms ''Keypress 

getSeq :: Keypress -> [Char] 
getSeq = uncurry replicate . view _Keypress 

इस बेहतर है? कोई जानकारी नहीं। आपके कोड में पैटर्न-मिलान मेरे लिए ठीक दिखता है, लेकिन यदि आप पहले से ही lens का उपयोग कर रहे हैं, तो यह संस्करण आपके लिए अधिक स्वीकार्य हो सकता है।

12

लिखित के रूप में, नहीं। लेकिन तुम ठीक कर सकते हैं कि अगर आप चाहते हैं:

data Keypress = Keypress 
    { count :: Int 
    , char :: Char } 
फिर

getSeq p = replicate (count p) (char p) 

और उस

getSeq = replicate <$> count <*> char 
संबंधित मुद्दे