2012-02-19 10 views
7

मैंने सोचा था कि ताकि आप की तरह साधारण रेंज जांच कर सकता है यह, हास्केल में मनमाने ढंग से श्रृंखलित तुलना करने के लिए स्वच्छ होगा अनुमान लगाने के लिए:हास्केल: GHC को प्रोत्साहित करना सही मध्यवर्ती प्रकार

x <= y < z 

और

की तरह अधिक जटिल सामान
x /= y < z == a 

कहाँ उपरोक्त दो शब्दार्थ

x <= y && y < z 
x /= y && y < z && z == a 

बस को देखकर मैं के बराबर हैं मैं काम करने के लिए वाक्यविन्यास मिल सकता है।

तो मैं जिस तरह से वहाँ प्रकार कक्षाओं की एक जोड़ी का उपयोग करने का सबसे मिल गया:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-} 
module ChainedOrd where 

import Prelude hiding ((<), (<=), (>), (>=), (==), (/=)) 

class Booly v a where 
    truthy :: v -> a 
    falsy :: v -> a 

instance Booly a Bool where 
    truthy = const True 
    falsy = const False 

instance Booly a (Maybe a) where 
    truthy = Just 
    falsy = const Nothing 

class ChainedOrd a b where 
    (<),(>),(<=),(>=),(==),(/=) :: (Booly b c) => a -> b -> c 

infixl 4 < 
infixl 4 > 
infixl 4 <= 
infixl 4 >= 
infixl 4 == 
infixl 4 /= 

instance Ord a => ChainedOrd a a where 
    x < y  = case compare x y of LT -> truthy y ; _ -> falsy y 
    x > y  = case compare x y of GT -> truthy y ; _ -> falsy y 
    x <= y = case compare x y of GT -> falsy y ; _ -> truthy y 
    x >= y = case compare x y of LT -> falsy y ; _ -> truthy y 
    x == y = case compare x y of EQ -> truthy y ; _ -> falsy y 
    x /= y = case compare x y of EQ -> falsy y ; _ -> truthy y 

instance Ord a => ChainedOrd (Maybe a) a where 
    Just x < y  = case compare x y of LT -> truthy y ; _ -> falsy y 
    Nothing < y = falsy y 
    Just x > y  = case compare x y of GT -> truthy y ; _ -> falsy y 
    Nothing > y = falsy y 
    Just x <= y = case compare x y of GT -> falsy y ; _ -> truthy y 
    Nothing <= y = falsy y 
    Just x >= y = case compare x y of LT -> falsy y ; _ -> truthy y 
    Nothing >= y = falsy y 
    Just x == y = case compare x y of EQ -> truthy y ; _ -> falsy y 
    Nothing == y = falsy y 
    Just x /= y = case compare x y of EQ -> falsy y ; _ -> truthy y 
    Nothing /= y = falsy y 

कौन सा ठीक संकलित है, लेकिन काफी चेनिंग, मध्यवर्ती प्रकार की समस्या की वजह से अनुमति देने के लिए प्रतीत नहीं होता।

-- works 
checkRange1 :: Ord a => a -> a -> a -> Bool 
checkRange1 x y z = x `lem` y <= z 
    where lem :: Ord a => a -> a -> Maybe a 
     lem = (<=) 

-- works 
checkRange2 :: Ord a => a -> a -> a -> Bool 
checkRange2 x y z = (x <= y) `leb` z 
    where leb :: Ord a => Maybe a -> a -> Bool 
     leb = (<=) 

checkRange1 और checkRange2 काम ठीक है, क्योंकि वे दोनों मध्यवर्ती प्रकार पर एक बाधा डाल (या तो पहले की तुलना, या दूसरे के लिए एक तर्क के रूप का एक परिणाम के रूप में)।

-- error 
checkRange3 :: Ord a => a -> a -> a -> Bool 
checkRange3 x y z = (x <= y) <= z 

जब मैं संकलक मध्यवर्ती प्रकार का अनुमान लगा देना करने की कोशिश है, हालांकि, यह मुझ पर भौंकता।

ChainedOrd.hs:64:30: 
    Ambiguous type variable `a0' in the constraints: 
     (ChainedOrd a0 a) arising from a use of `<=' 
         at ChainedOrd.hs:64:30-31 
     (Booly a a0) arising from a use of `<=' at ChainedOrd.hs:64:24-25 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the expression: (x <= y) <= z 
    In an equation for `checkRange3': checkRange3 x y z = (x <= y) <= z 

वहाँ किसी भी तरह से मैं संकलक है कि यह मध्यवर्ती प्रकार a0Booly a a0, ChainedOrd a0 a satisifying रूप Maybe a का उपयोग करना चाहिए समझा सकते है, के बाद से है कि केवल उदाहरण इसके बारे में पता है?

यह असफल रहा, क्या मैं एक और तरीका है जो मैं मनमाने ढंग से तुलना करने के लिए काम कर सकता हूं?

+1

क्या आपको यह प्रश्न पढ़ने पर विचार आया था (http://stackoverflow.com/questions/9284350/why-does-1-in-1-0-true-evaluate-to-false)? जब मैंने इसे पढ़ा तो मैंने सोचा कि यह सुविधा कितनी उपयोगी है, फिर भी मजबूत मजबूत स्थैतिक टाइपिंग की अनुपस्थिति में खतरनाक है क्योंकि पाइथन ऑफर नहीं कर सकता है। दयालुता यह हैस्केल में अपनी तरह की प्रणाली के साथ काफी अच्छी तरह से काम नहीं कर रही है जो इस सुरक्षा की पेशकश करता है। – leftaroundabout

+0

@ बाएंअराउंडबाउट वास्तव में, मुझे यह [जूलिया भाषा के लिए इस मैनुअल] से मिला है (http://julialang.org/manual/mathematical-operations/#Numeric+Comparisons) – rampion

उत्तर

5
infixl 4 ==? 

class ChainedEq a b where 
    (==?) :: a -> b -> Maybe b 

instance (Eq a) => ChainedEq (Maybe a) a where 
    x ==? y = if x == Just y 
    then x 
    else Nothing 

instance (Eq a) => ChainedEq a a where 
    x ==? y = if x == y 
    then Just x 
    else Nothing 

unChain :: Maybe a -> Bool 
unChain Nothing = False 
unChain (Just _) = True 

test :: Int -> Int -> Int -> Bool 
test x y z = unChain $ x ==? y ==? z 
+0

'unChain' =' isJust' – rampion

+0

मुझे यह दृष्टिकोण पसंद है – rampion

+0

मेरा मानना ​​है कि इस पैटर्न को आसानी से "चेनडऑर्ड" –

4

तरीके संकलक किस प्रकार उपयोग करने के लिए बताने के लिए कर रहे हैं,

checkRange4 x y z = ((x <= y) `asTypeOf` Just x) <= z 

या आप ScopedTypeVariables उपयोग कर सकते हैं, गुंजाइश में प्रकार चर लाने के लिए और x <= y पर एक प्रकार हस्ताक्षर डाल दिया। लेकिन आप संकलक को केवल उन उदाहरणों का उपयोग करने के लिए नहीं बता सकते हैं जो इसके बारे में जानते हैं। कंपाइलर एक खुली दुनिया धारणा पर काम करता है, अन्य उदाहरणों को परिभाषित किया जा सकता है, और कोड को काम करना पड़ता है यदि वे हैं और दायरे में आते हैं। तो तुम जो कुछ भी करते हैं की तुलना में

checkRange5 x y z = x <= y && y <= z 
3

यहां बताया गया है कि मैं यह करना होगा और अधिक भद्दा हो जाएगा:

{-# LANGUAGE NoMonomorphismRestriction #-} 

data Chain v e = Link { evaluation :: e 
         , val :: v 
         , next :: Chain v e 
         } 
       | Start { val :: v } 


liftChain :: (a -> a -> b) -> Chain a b -> a -> Chain a b 
liftChain f ch x = Link { evaluation = val ch `f` x, val = x, next = ch } 

(.<) = liftChain (<) 
(.>) = liftChain (>) 
(.<=) = liftChain (<=) 
(.>=) = liftChain (>=) 
(.==) = liftChain (==) 

toList :: Chain v e -> [v] 
toList (Start v) = [v] 
toList (Link _ v n) = v : toList n 

toList' :: Chain v e -> [e] 
toList' (Start _) = [] 
toList' (Link e _ n) = e : toList' n 

and' :: Chain v Bool -> Bool 
and' = and . toList' 

उपयोग:

ghci> and' $ Start 3 .< 4 .< 7 .== 7 .< 9 .>= 0 .== (2-2) 
True 
+0

जटिल भाषा सुविधाओं के बीच व्यापार की तुलना करना दिलचस्प है और अतिरिक्त वाक्य रचनात्मक शक्ति। मेरे संस्करण को हास्केल 98 से परे कुछ भी नहीं चाहिए, लेकिन अनिवार्य 'स्टार्ट' वाक्यविन्यास की कीमत पर आता है। ट्राइनिथिस के समाधान के लिए कुछ भाषा एक्सटेंशन की आवश्यकता होती है, जो इसे 'स्टार्ट' को खत्म करने की शक्ति खरीदती है, लेकिन इसे अभी भी 'अनचेन' की आवश्यकता होती है (मेरे 'और' के साथ तुलनीय)। यहां तक ​​कि इसे खत्म करने का एक तरीका भी हो सकता है, लेकिन मुझे इस तरह की चीज़ से अनजान है, और निश्चित रूप से कुछ शक्तिशाली एक्सटेंशन और शायद अधिक घुसपैठ करने वाले प्रीलूड प्रतिस्थापन की आवश्यकता होगी। –

+1

आप कुछ स्थितियों में 'स्टार्ट' से छुटकारा पा सकते हैं (जैसे आपका उपरोक्त उदाहरण) यदि आप 'न्यू ए => चेन ए बूल' को 'न्यू' का उदाहरण देते हैं। – rampion

1

यह मुझे इस सका है कि कोई आराम दिया अजीब समाप्ति/अनपॅकिंग कार्यों के बिना स्पष्ट नहीं लगता है।क्या मैं के साथ आया था विशुद्ध रूप से अनुमति देने के लिए इन्फ़िक्स-श्रृंखलित भाव:

{-# LANGUAGE MultiParamTypeClasses  #-} 
{-# LANGUAGE FlexibleInstances   #-} 
{-# LANGUAGE FlexibleContexts   #-} 
{-# LANGUAGE TypeFamilies    #-} 

module ChainedComp where 

infixl 4 ==.. , .==. , ==? 

data Comp1Chain a = Sofar1OK a | Already1Failed 
data Comp2Chain a = Sofar2OK a | Already2Failed 
data Comp3Chain a = Sofar3OK a | Already3Failed 
-- ... 

(==..) :: (Eq a) => a -> a -> Comp1Chain a 
x==..y | x==y  = Sofar1OK y 
     | otherwise = Already1Failed 

class ChainableComp c where 
    type AppendElem c :: * 
    type ChainAfterAppend c :: * 
    (.==.) :: c -> AppendElem c -> ChainAfterAppend c 
    (==?) :: c -> AppendElem c -> Bool 


instance (Eq a) => ChainableComp (Comp1Chain a) where 
    type AppendElem (Comp1Chain a) = a 
    type ChainAfterAppend (Comp1Chain a) = Comp2Chain a 
    chn.==.y | (Sofar1OK x)<-chn, x==y = Sofar2OK x 
      | otherwise    = Already2Failed 
    chn==?y | (Sofar1OK x)<-chn, x==y = True 
      | otherwise    = False 
instance (Eq a) => ChainableComp (Comp2Chain a) where 
    type AppendElem (Comp2Chain a) = a 
    type ChainAfterAppend (Comp2Chain a) = Comp3Chain a 
    chn.==.y | (Sofar2OK x)<-chn, x==y = Sofar3OK x 
      | otherwise    = Already3Failed 
    chn==?y | (Sofar2OK x)<-chn, x==y = True 
      | otherwise    = False 
-- ... 

और उस के साथ, आप

*ChainedComp> 7 ==..7.==.7==? 7 
True 
*ChainedComp> 7 ==..7.==.6==? 7 
False 
*ChainedComp> 5 ==..5.==.5.==.4.==.5.==.5==? 5 
False 

ऐसा नहीं है सुंदर, या तो है, लेकिन IMO बेहतर अन्य समाधान की तुलना में पठनीय लिख सकते हैं। आवश्यक उदाहरण घोषणाओं की मात्रा निश्चित रूप से बहुत अच्छी नहीं है, लेकिन यह एक बार और सभी के लिए है, इसलिए मुझे लगता है कि यह बहुत बुरा नहीं है।

+0

इस बिंदु पर, विभिन्न खोलने, जारी रखने और बंद करने वाले ऑपरेटरों के साथ, मुझे टाइपक्लास के लिए कोई आवश्यकता नहीं दिखाई देती है - यह केवल 'हो सकता है' और सामान्य ऑपरेटरों के साथ किया जा सकता है: https://gist.github.com/1871093 – rampion

+0

ओह, तुम पूरी तरह से सही हो। इसे मूल रूप से केवल दो अलग-अलग ऑपरेटरों के साथ काम करना था और मुझे लगता है कि यह उन प्रकार के परिवारों के बिना काम नहीं कर रहा था - न ही उनके साथ, जैसा कि यह निकला ... या क्या मैं कर सकता हूं? प्रतीक्षा करें ... – leftaroundabout

+0

नहीं ... समस्या यह है कि संबंधित प्रकार समानार्थी उदाहरण ओवरलैपिंग उदाहरणों में काम नहीं कर सकते हैं। – leftaroundabout

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