यह प्रयास के अनुभवहीन तरीका नहीं है, कि इस तरह दिखता है:
route :: Graph -> Label -> Label -> Bool
route g dest from | from == dest = True
route g dest from = any (route g dest) (neighbours g from)
लेकिन उस रेखांकन पाशन में विफल रहता है। (मुझे यह भी लगता है कि आपके पास पड़ोसियों को परिभाषित किया गया है)
तो, क्या करना है लेकिन पहले से देखे गए नोड्स की सूची को पास करना है।
route2 :: Graph -> Label -> Label -> [Label] -> Bool
route2 g dest from seen
| dest == from = True
| otherwise = any (\x -> route2 g dest x (from:seen)) (neighbours g from)
लेकिन अगर आप ग्राफ यहाँ पर यह चल रहे थे। आप एक निशान है कि (कुछ इस तरह योजना बहाना देखा मिलेगा, मैं बेशर्म मेरी सीएस वर्ग से इन चित्रों को चोरी कर लिया है fr है खोजने के मार्ग, और fr-एल कि एक सूची लेता है इसका एक संस्करण है। दूसरा पैरामीटर संचायक)
आप देख सकते हैं है, यह नोड्स कश्मीर और एच दो बार दौरा समाप्त होता है। यह बुरा है, देखते हैं कि यह क्यों कर रहा है।
चूंकि यह any
में रिकर्सिव कॉल से किसी भी जानकारी का बैक अप नहीं लेता है, तो यह नहीं देख सकता कि यह शाखाओं में क्या हुआ जो असफल रहा, केवल वर्तमान नोड के पथ पर क्या था।
अब इसे ठीक करने के लिए, हम दो पथ ले सकते हैं। मेरी कक्षा ने एक सतत उत्तीर्ण दृष्टिकोण लिया जो कि उपन्यास है, इसलिए मैं इसे राज्य के मोनड संस्करण से पहले दिखाऊंगा।
routeC :: Graph -> Label -> Label -> [Label] -> ([Label] -> Bool) -> Bool
routeC g dest from seen k
| dest == from = True
| from `elem` seen = k (from:seen)
| otherwise = routeCl g dest (neighbours g from) (from:seen) k
routeCl :: Graph -> Label -> [Label] -> [Label] -> ([Label] -> Bool) -> Bool
routeCl g dest [] seen k = k seen
routeCl g dest (x:xs) seen k =
routeC g dest x seen (\newSeen -> routeCl g dest xs newSeen k)
यह किसी भी के बजाय कार्यों की एक जोड़ी का उपयोग करता है। routeC
बस यह देखने के लिए जांचता है कि क्या हम गंतव्य पर पहुंचे हैं, या यदि हमने लूप किया है, अन्यथा यह वर्तमान नोड के पड़ोसियों के साथ रूटसीएल को कॉल करता है।
यदि हमने लूप किया है, तो केवल False
लौटने की बजाय, हम निरंतरता को कॉल करते हैं, लेकिन उन नोड्स के साथ जिन्हें हमने वर्तमान में देखा है (वर्तमान में सहित)।
routeCL
नोड्स की एक सूची लेता है, और यदि सूची खाली है, तो निरंतरता चलाता है, अन्यथा यह कुछ दिलचस्प करता है। यह पहले नोड पर routeC
चलाता है, और इसे एक निरंतरता पास करता है जो शेष नोड्स की नई सूची के साथ शेष सूची में routeCl
चलाएगा। तो यह असफल शाखाओं के इतिहास में देखने में सक्षम हो जाएगा।
(एक अतिरिक्त चीज़ के रूप में, हम इसे थोड़ा और सामान्य कर सकते हैं, और इसे निरंतर उत्तीर्ण शैली में बदल सकते हैं। मैंने कार्यों की जोड़ी का उपयोग करने के बजाय किसी भी को सामान्यीकृत किया है। यह वैकल्पिक है, और प्रकार हस्ताक्षर आप के लिए, राज्य इकाई संस्करण क्या इंतजार कर रहे थे के लिए,
anyK :: (a -> s -> (s -> r) -> (s -> r) -> r) ->
[a] -> s -> (s -> r) -> (s -> r) -> r
anyK p [] s tK fK = fK s
anyK p (x:xs) s tK fK = p x s tK (\s' -> anyK p xs s' tK fK)
routeK2 :: Graph -> Label -> Label -> ([Label] -> r) -> ([Label] -> r) -> r
routeK2 g dest from' trueK falseK = route from' [] trueK falseK
where route from seen tK fK
| from == dest = tK seen
| from `elem` seen = fK seen
| otherwise = anyK route (neighbours g from) (from:seen) tK fK
यही बात है, लेकिन अधिक जानकारी के साथ में पारित किया जा रहा कोड से डरावना है।)।
अब।
routeS :: Graph -> Label -> Label -> State [Label] Bool
routeS g dest from | dest == from = return True
routeS g dest from = do
seen <- get
if from `elem` seen then return False else do
put (from:seen)
anyM (routeS g dest) (neighbours g from)
लेकिन उस अंतिम पंक्ति, क्या हम साथ शुरू की तरह एक बहुत कुछ नहीं दिखता है तो बस कुछ अतिरिक्त पाइपलाइन के साथ? तुलना करें:
any (route g dest) (neighbours g from) -- Simple version
anyM (routeS g dest) (neighbours g from) -- State Version
anyK route (neighbours g from) (from:seen) tK fK -- CPS version
कोर पर, सभी तीन एक ही काम कर रहे हैं। राज्य संस्करण में मोनड हमारे लिए देखे गए नोड्स की नलसाजी को अच्छी तरह से संभालता है।और सीपीएस संस्करण हमें दिखाता है कि राज्य के मोनैड की तुलना में अधिक स्पष्ट फैशन में नियंत्रण का प्रवाह कैसा होगा।
ओह, लेकिन anyM
मानक लाइब्रेरी में प्रतीत नहीं होता है। यहां यह दिखता है:
anyM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
anyM p [] = return False
anyM p (x:xs) = do
y <- p x
if y
then return True
else anyM p xs
@ डैनियल इस प्रकार को ध्यान में रखते हुए धन्यवाद ... बस इसे मेरे emacs से काटने और चिपकाने के बिना टाइप किया। (^। ^) –