2017-04-05 4 views
11

मैं एक हास्केल रूकी हूं और मुझे अक्सर अपने सदस्य में से किसी एक को फ़ंक्शन लागू करने के लिए पैटर्न मिलान के साथ डेटा को विघटित करना पड़ता है और फिर उसे फिर से इकट्ठा करना पड़ता है।क्या हास्केल किसी फ़ंक्शन को डेटा सदस्य को मैप करने का तरीका प्रदान करता है?

मेरे पास है कहते हैं:

data Car = Car { gas :: Int, licensePlate :: String } 

और मैं इसे अपने गैस को आधा करने के लिए जब यह ड्राइव, और यह फिर से ईधन देना चाहते हैं, तो मैं कर रहा हूँ:

mapGas:: (Int -> Int) -> Car -> Car 
mapGas f (Car aGas aLicensePlate) = Car (f aGas) aLicensePlate 

drive:: Car -> Car 
drive = mapGas (flip div 2) 

refuel:: Int -> Car -> Car 
refuel = mapGas . (+) 

सिर्फ करने के लिए एक रास्ता है कि सहायक फंक्शन mapGas को परिभाषित किए बिना? चूंकि यह कई क्षेत्रों के बने होने पर डेटा के प्रत्येक सदस्य के लिए नक्शा फ़ंक्शन लिखने के बजाय परेशान हो सकता है। मैं जानता हूँ कि यह accessors साथ सदस्यों में से एक के लिए एक मूल्य निर्दिष्ट करना संभव है:

runOutOfFuel:: Car -> Car 
runOutOfFuel aCar = aCar { gas = 0 } 

यह accessors भी साथ एक समारोह मैप करने के लिए संभव है? यदि हां, तो कैसे?

+2

मुझे लगता है कि आप में से कुछ ध्यान देना चाहिए 'lens' ट्यूटोरियल https://hackage.haskell.org/package/lens – epsilonhalbe

+0

बस रिकार्ड के लिए, लेंस के बिना, मुझे लगता है कि सबसे अच्छा आप कर सकते हैं' है mapGas च = (\ कार -> कार {गैस = एफ (गैस कार)}) '। यह कम से कम अन्य क्षेत्रों का जिक्र करने से बचाता है। – chi

+0

@chi मैं आमतौर पर उन मामलों में जो करता हूं वह समरूपता को संरक्षित करने का प्रयास करता है: 'mapGas f = (\ car @ car {gas = g} -> कार {gas = f g}) '। लंबा, लेकिन आप '->' के दोनों किनारों पर 'गैस' फ़ील्ड देख सकते हैं। – Alec

उत्तर

13

केवल कोर पुस्तकालयों का उपयोग करना? नहीं, लेकिन व्यापक रूप से lens पैकेज के साथ, हां। आप आसानी से// सेट प्राप्त कर सकते हैं जो फ़ील्ड डेटा संरचनाओं में नेस्ट कर रहे हैं, संशोधित करने,

{-# LANGUAGE TemplateHaskell #-} 

import Control.Lens.TH 
import Control.Lens 

data Car = Car { _gas :: Int, _licensePlate :: String } 

makeLenses ''Car 

अब: यहाँ है कि आपके मामले में ऐसा दिखाई देता है।

runOutOfFuel:: Car -> Car 
runOutOfFuel = gas .~ 0 

drive:: Car -> Car 
drive = gas %~ (`div` 2) 

refuel:: Int -> Car -> Car 
refuel c = gas +~ c 

जादू है कि यहाँ makeLenses ''Car को gas और licensePlate कार्यों है कि इसी तरह (लेकिन अधिक शक्तिशाली) कर रहे हैं उत्पन्न करता है अपने mapGas (mapGas = (gas %~) वास्तव में,)। lens के साथ शुरू करना बहुत कठिन है, लेकिन मैं केवल examples अनुभाग पढ़ने की अनुशंसा करता हूं।

+0

'डेटा। डेटा 'और' जीएचसी.जेनरिक्स '' मूल' में हैं और इसके लिए इसका उपयोग किया जा सकता है, लेकिन मैं मानता हूं कि 'लेंस' आमतौर पर प्राकृतिक पसंद –

+0

है, मैं इस 'लेंस' ट्यूटोरियल की भी सिफारिश करता हूं (यदि आप चाहते हैं 'लेंस' को बेहतर समझने के लिए): https://artyom.me/lens-over-tea-1 – Shersh

+0

मैं पूरी तरह से "सुंदर चुनौतीपूर्ण" से सहमत हूं। कभी-कभी मुझे लगता है कि व्यावहारिक आम मामलों से परे यह थोड़ा अधिक सामान्य था। – chi

4

कोई भाषा सुविधा है जो यह करता है, लेकिन, हास्केल में कई चीजों के साथ, मूल भाषा पर्याप्त शक्तिशाली है कि इसे सरल और सुरुचिपूर्ण तरीके से कार्यान्वित किया जा सकता है।

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

लेंस के लिए एक परिचय है जो मुझे here पसंद है। उदाहरणों का उपयोग करने के लिए, आपको lens पैकेज की आवश्यकता होगी। (Or this one if you're using Stack)

+5

मुझे नहीं पता कि मैं कहूंगा कि लेंस का अस्तित्व सबूत है कि मूल भाषा पर्याप्त शक्तिशाली है। लेंस सृजन स्पष्ट रूप से कोर भाषा के बाहर किया जाता है, टेम्पलेट हैकेल का उपयोग कोड का एक गुच्छा उत्पन्न करने के लिए करता है क्योंकि कोर भाषा सामान्य रूप से उस कोड को सामान्य तरीके से लिखे जाने के लिए पर्याप्त शक्तिशाली नहीं होती है और फिर पुन: उपयोग की जाती है। – amalloy

+1

आप वास्तव में टेम्पलेट्स का उपयोग किए बिना लेंस बना सकते हैं, ऐसा करने के लिए लोग बस थोड़ा कठिन हो जाते हैं ताकि लोग इसे व्यवस्थित करने के लिए टेम्पलेट का उपयोग कर सकें।शक्तिशाली होने के नाते, मेरा मतलब था कि इस अर्थ में कि बहुत सारी चीजें जिन्हें अन्य प्रोग्रामिंग भाषाओं में हार्ड-कोड करने की आवश्यकता है, को हास्केल में परिभाषित किया जा सकता है। –

+0

@amalloy लेंस निर्माण केवल बॉयलरप्लेट को कम करने के लिए templating के साथ किया जाता है। आप हाथ से सभी लेंस कार्यों को लिख सकते हैं, यह सिर्फ चूसना होगा। – Daenyth

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

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