2015-06-01 2 views
6

मैं हास्केल के लिए काफी नया हूं और makeLensesControl.Lens से और कक्षाओं की बाधाओं को एक साथ समानार्थी शब्द टाइप करने के लिए अपने कार्यों के प्रकार को अधिक कॉम्पैक्ट (पठनीय?) बनाने के लिए उपयोग करना चाहता हूं।मेकलेन्स, कक्षा बाधाओं और समानार्थी समानार्थी शब्दों का उपयोग

मैंने कम से कम डमी उदाहरण के साथ आने का प्रयास किया है ताकि मैं यह प्रदर्शित कर सकूं कि मैं क्या हासिल करना चाहता हूं और उदाहरण इस से कोई अन्य उद्देश्य नहीं प्रदान करता है।

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

मिनिमल उदाहरण

एक उदाहरण है, मैं निम्नलिखित डेटा प्रकार को परिभाषित कहना है:

data State a = State { _a :: a 
        } deriving Show  

है, जिसके लिए मैं भी लेंस बनाने:

makeLenses ''State 

आदेश को लागू करने के प्रकार पैरामीटर a पर एक वर्ग बाधा प्रकार निर्माता State द्वारा उपयोग किया गया मैं एक स्मार्ट कन्स्ट्रक्टर का उपयोग करता हूं :

doStuff :: Num a => State a -> State a 
doStuff s = s & a %~ (*2) 

यह सब काम करता है के रूप में इरादा, उदाहरण के लिए:

test = doStuff . mkState $ 5.5 -- results in State {_a = 11.0} 

समस्या

mkState :: (Num a) => a -> State a 
mkState n = State {_a = n} 

इसके बाद, मैं इस के समान प्रकार हस्ताक्षरों के साथ काम करता है की एक संख्या है कहना

मैंने निम्न प्रकार के समानार्थी शब्द का उपयोग करने का प्रयास किया है:

type S = (Num n) => State n -- Requires the RankNTypes extensions 

, एक साथ के साथ:

{-# LANGUAGE RankNTypes #-} 

, doStuff के प्रकार के हस्ताक्षर को आसान बनाने के प्रयास में:

doStuff :: S -> S 

, लेकिन यह निम्न त्रुटि देता है:

Couldn't match type `State a0' with `forall n. Num n => State n' 
    Expected type: a0 -> S 
    Actual type: a0 -> State a0 
In the second argument of `(.)', namely `mkState' 
    In the expression: doStuff . mkState 
    In the expression: doStuff . mkState $ 5.5 
Failed, modules loaded: none. 

प्रश्न

हास्केल का मेरा वर्तमान ज्ञान उपर्युक्त त्रुटि का कारण समझने के लिए पर्याप्त नहीं है। मुझे आशा है कि कोई व्यक्ति समझा सकता है कि त्रुटि का कारण क्या है और/या समानार्थी नाम बनाने के अन्य तरीकों का सुझाव देता है या ऐसा क्यों समानार्थी संभव नहीं है।

पृष्ठभूमि

मेरे मूल समस्या इस के करीब लग रहा है:

data State r = State { _time :: Int 
        , _ready :: r 
        } deriving Show 

makeLenses ''State 

data Task = Task { ... } 
यहाँ मैं Queue वर्ग का एक उदाहरण जा रहा है निम्नलिखित स्मार्ट निर्माता का उपयोग कर _ready के प्रकार लागू करना चाहते हैं

:

mkState :: (Queue q) => Int -> q Task -> State (q Task) 
mkState t q = State { _time = t 
        , _ready = q 
        } 

मैं भी प्रकार हस्ताक्षर के साथ काम करता है की एक संख्या है Tures इस के समान:

updateState :: Queue q => State (q Task) -> Task -> State (q Task) 
updateState s x = s & ready %~ (enqueue x) & time %~ (+1) 

मैं एक प्रकार पर्याय S का उपयोग करने के रूप में इस तरह के कार्यों के प्रकार के पुनर्लेखन के लिए सक्षम होने के लिए करना चाहते हैं:

updateState :: S -> Task -> S 

, लेकिन पहले कम से कम उदाहरण मैं डॉन के साथ के रूप में यह नहीं पता कि कैसे समानार्थी शब्द S परिभाषित किया जाए या यह संभव है या नहीं।

हो सकता है कि वहाँ प्रकार हस्ताक्षर को आसान बनाने की कोशिश कर रहा में कोई वास्तविक लाभ है?

संबंधित पढ़ने

मैं इतने पर निम्न संबंधित सवाल पढ़ा है:

यह भी संबंधित हो सकती है लेकिन मेरे वर्तमान समझ दी हास्केल का मैं वास्तव में इसे सब कुछ नहीं समझ सकता:

फ़ॉलो-अप

के बाद से मैं कुछ हास्केल करने का अवसर मिला है यह एक समय हो गया है। @bheklilr के लिए धन्यवाद अब मैंने केवल एक प्रकार के समानार्थी को अगली प्रकार की त्रुटि को हिट करने में कामयाब रहा है जिसे मैं अभी भी समझने में सक्षम नहीं हूं। मैंने नई प्रकार की त्रुटि के संबंध में निम्नलिखित अनुवर्ती प्रश्न Type synonym causes type error पोस्ट किया है।

+1

क्या एक अच्छी तरह से पूछे जाने वाले प्रश्न। बहुत बढ़िया। – AndrewC

उत्तर

2

आप . ऑपरेटर के संयोजन और RankNTypes के उपयोग के कारण विशेष रूप से त्रुटि को देखते हैं। आप

test = doStuff $ mkState 5.5 

या यहाँ तक कि

test = doStuff (mkState 5.5) 

को

test = doStuff . mkState $ 5.5 

से इसे बदल अगर यह संकलन होगा। ऐसा क्यों है?प्रकार को देखो:

doStuff :: forall n. Num n => State n -> State n 
mkState :: Num n => n -> State n 

(doStuff) . (mkState) <===> (forall n. Num n => State n -> State n) . (Num n => n -> State n) 

उम्मीद है कि कोष्ठकों मदद इसे यहाँ स्पष्ट, doStuff के लिए forall n. Num n ... से n बनाने mkState के लिए Num n => ... से एक अलग प्रकार चर रहा है क्योंकि forall के दायरे केवल के अंत तक फैली कोष्ठक। तो ये कार्य वास्तव में रचना नहीं कर सकते क्योंकि संकलक उन्हें अलग प्रकार के रूप में देखता है! वहाँ वास्तव में विशेष रूप से इस कारण के लिए ठीक ST इकाई का उपयोग कर, बस ताकि आप runST $ do ... कर सकते हैं के लिए $ ऑपरेटर के लिए विशेष नियम हैं।

आप क्या आप GADTs का उपयोग कर आसान चाहते हैं को पूरा करने में सक्षम हो सकता है, लेकिन मैं नहीं मानता lens 'TemplateHaskell GADT प्रकार के साथ काम करेंगे। हालांकि, आप इस मामले में अपना खुद का आसानी से लिख सकते हैं, इसलिए यह एक सौदा का बड़ा नहीं है।


एक और स्पष्टीकरण:

doStuff . mkState $ 5.5 

से

doStuff $ mkState 5.5 

पहले एक में बहुत अलग है, doStuff का कहना है कि सभी प्रकार n के लिए Num, अपने प्रकार State n -> State n है, जबकि mkState कहते हैं के लिए कुछNum प्रकार m, अपने प्रकार m -> State m है। इन दो प्रकार के, क्योंकि "सभी के लिए" और quantifications (इसलिए ExistentialQuantification) "कुछ के लिए", रचना के बाद से उन्हें मतलब यह होगा कि कुछ Num m के लिए आप सभी Num n उत्पादन कर सकते हैं की ही नहीं हैं।

doStuff $ mkState 5.5 में, आप का

(forall n. Num n => State n -> State n) $ (Num m => State m) 

सूचना बराबर है कि प्रकार $ के बाद एक समारोह क्योंकि mkState 5.5 पूरी तरह से लागू किया जाता है नहीं है। तो यह काम करता है क्योंकि सभी के लिए Num n आप State n -> State n कर सकते हैं, और आप इसे कुछ Num m => State m प्रदान कर रहे हैं। यह सहजता से काम करता है। फिर, यहां अंतर बनाम बनाम अनुप्रयोग है। आप किसी ऐसे फ़ंक्शन को लिख नहीं सकते जो किसी प्रकार के फ़ंक्शन के साथ काम करता है जो कि सभी प्रकारों पर काम करता है, लेकिन आप किसी ऐसे फ़ंक्शन पर एक मान पास कर सकते हैं जो सभी प्रकारों पर काम करता है ("सभी प्रकार" यहां अर्थ forall n. Num n => n)।

+0

आप @bheklilr धन्यवाद, यह एक तरह से समझ बनाने के कर रहा हूँ, हालांकि मैं अभी तक पूरी तरह समझ में नहीं आता क्यों mkState 5 <==> 'doStuff $ करने के लिए बदल रहा है (। N forall Num एन => राज्य n -> राज्य एन) $ (Num एन => n -> राज्य एन) 'इसे हल करता है। जहां तक ​​मैं समझता हूं कि अब हमारे पास $ dostuff $ mkState 5 <==> है (forall n। Num n => राज्य n -> राज्य n) $ (राज्य पूर्णांक) '। क्या यह '$' ऑपरेटर के विशेष नियमों के कारण है, आप उल्लेख करते हैं कि कंपाइलर अब '' '' के 'बाईं ओर '' '' '' '' '' '' '' '' '' '' '' '' के ' –

+0

मैंने संक्षेप में [क्लास बाधा के लिए वैकल्पिक समाधान के रूप में जीएडीटी] में देखा है (http://stackoverflow.com/questions/21505975/write-gadt-record-with-constrained-type) इस प्रश्न को पहले से पोस्ट करने पर, लेकिन जब से मैं ' मैं हास्केल और लेंस के लिए नया हूं, मैंने सोचा था कि मैं अपने स्वयं के लेंस बनाने की तुलना में 'मेकलेन्स' का उपयोग करके बेहतर था (http://stackoverflow.com/questions/28145369/makelenses-for-gadts-haskell)। एक बार जब मैं हास्केल और लेंस के साथ अधिक अनुभवी हो जाता हूं तो मैं जांच कर सकता हूं कि मेरे अपने लेंस को कैसे परिभाषित किया जाए। –

+0

शायद आप (@ करलमार्ककंड) 'doStuff के बजाय' (doStuff। MkState) $ 5.5' लिखने का इरादा रखते हैं। mkState $ 5.5'। इस प्रकार समस्या ऑपरेटर प्राथमिकता से संबंधित प्रतीत होती है, इस प्रकार पार्सिंग, और कुछ भी जटिल नहीं है। –

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