Haskell Language
सामान्य जीएचसी भाषा एक्सटेंशन
खोज…
टिप्पणियों
ये भाषा एक्सटेंशन आमतौर पर ग्लासगो हास्केल कंपाइलर (जीएचसी) का उपयोग करते समय उपलब्ध होते हैं क्योंकि वे अनुमोदित हास्केल 2010 भाषा रिपोर्ट का हिस्सा नहीं होते हैं। इन एक्सटेंशनों का उपयोग करने के लिए, किसी को एक झंडे का उपयोग करके या तो कंपाइलर को सूचित करना चाहिए या किसी फ़ाइल में module
कीवर्ड से पहले एक LANGUAGE
प्रोग्राम रखना चाहिए। आधिकारिक दस्तावेज जीसीएच उपयोगकर्ता गाइड के खंड 7 में पाया जा सकता है।
LANGUAGE
प्रोग्राम का प्रारूप {-# LANGUAGE ExtensionOne, ExtensionTwo ... #-}
। वह शाब्दिक {-#
जिसके बाद LANGUAGE
उसके बाद एक्सटेंशन की अल्पविराम से अलग सूची है, और अंत में समापन #-}
। एक LANGUAGE
कई LANGUAGE
कार्यक्रम रखे जा सकते हैं।
MultiParamTypeClasses
यह एक बहुत ही सामान्य विस्तार है जो कई प्रकार के मापदंडों के साथ टाइप कक्षाएं देता है। आप एमपीटीसी को प्रकारों के बीच के संबंध के रूप में सोच सकते हैं।
{-# LANGUAGE MultiParamTypeClasses #-}
class Convertable a b where
convert :: a -> b
instance Convertable Int Float where
convert i = fromIntegral i
मापदंडों का क्रम मायने रखता है।
एमपीटीसी कभी-कभी टाइप परिवारों के साथ प्रतिस्थापित किया जा सकता है।
FlexibleInstances
नियमित उदाहरणों की आवश्यकता होती है:
All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
इसका मतलब है कि, उदाहरण के लिए, जब आप [a]
लिए एक उदाहरण बना सकते हैं, तो आप विशेष रूप से [Int]
लिए एक उदाहरण नहीं बना सकते हैं; FlexibleInstances
राहत मिलती है:
class C a where
-- works out of the box
instance C [a] where
-- requires FlexibleInstances
instance C [Int] where
OverloadedStrings
आम तौर पर, हास्केल में स्ट्रिंग शाब्दिक में एक प्रकार का String
(जो [Char]
लिए एक प्रकार का उपनाम है)। हालांकि यह छोटे, शैक्षिक कार्यक्रमों के लिए समस्या नहीं है, लेकिन वास्तविक दुनिया के अनुप्रयोगों में अक्सर Text
या ByteString
जैसे अधिक कुशल भंडारण की आवश्यकता होती है।
OverloadedStrings
बस के प्रकार को शाब्दिक रूप से बदलता है
"test" :: Data.String.IsString a => a
उन्हें इस तरह के प्रकार की अपेक्षा करने वाले कार्यों के लिए सीधे पारित किया जाना। कई लाइब्रेरी इस इंटरफ़ेस को अपने स्ट्रिंग-जैसे प्रकारों के लिए कार्यान्वित करते हैं जिनमें Data.Text और Data.ByteString शामिल हैं जो दोनों [Char]
पर निश्चित समय और स्थान लाभ प्रदान करते हैं।
OverloadedStrings
कुछ अनूठे उपयोग भी हैं जैसे कि Postgresql-simple पुस्तकालय से जो एसक्यूएल प्रश्नों को सामान्य स्ट्रिंग की तरह दोहरे उद्धरणों में लिखने की अनुमति देता है, लेकिन अनुचित इंजेक्शन के खिलाफ सुरक्षा प्रदान करता है, SQL इंजेक्शन हमलों का एक कुख्यात स्रोत।
IsString
वर्ग का एक उदाहरण बनाने के लिए आपको fromString
फ़ंक्शन का fromString
करना होगा। उदाहरण † :
data Foo = A | B | Other String deriving Show
instance IsString Foo where
fromString "A" = A
fromString "B" = B
fromString xs = Other xs
tests :: [ Foo ]
tests = [ "A", "B", "Testing" ]
† लिंडन Maydwell (का यह उदाहरण शिष्टाचार sordina
GitHub पर) पाया यहाँ ।
TupleSections
एक सिंटैक्टिक एक्सटेंशन जो एक प्रकार से ट्यूपल कंस्ट्रक्टर (जो एक ऑपरेटर है) को आवेदन करने की अनुमति देता है:
(a,b) == (,) a b
-- With TupleSections
(a,b) == (,) a b == (a,) b == (,b) a
एन-tuples
यह दो से अधिक की संख्या के साथ टुपल्स के लिए भी काम करता है
(,2,) 1 3 == (1,2,3)
मानचित्रण
यह उन अन्य स्थानों पर उपयोगी हो सकता है, जहां वर्गों का उपयोग किया जाता है:
map (,"tag") [1,2,3] == [(1,"tag"), (2, "tag"), (3, "tag")]
इस विस्तार के बिना उपरोक्त उदाहरण इस तरह दिखेगा:
map (\a -> (a, "tag")) [1,2,3]
UnicodeSyntax
एक एक्सटेंशन जो आपको कुछ अंतर्निहित ऑपरेटरों और नामों के बदले में यूनिकोड वर्णों का उपयोग करने की अनुमति देता है।
ASCII | यूनिकोड | का प्रयोग करें (रों) |
---|---|---|
:: | ∷ | प्रकार है |
-> | → | फंक्शन टाइप, लंबदा, case ब्रांच आदि। |
=> | ⇒ | वर्ग की कमी |
forall | ∀ | स्पष्ट बहुरूपता |
<- | ← | do अंकन |
* | ★ | प्रकार (या प्रकार) के प्रकार (जैसे, Int :: ★ ) |
>- | ⤚ | proc अंकन के लिए Arrows |
-< | ⤙ | proc अंकन के लिए Arrows |
>>- | ⤜ | proc अंकन के लिए Arrows |
-<< | ⤛ | proc अंकन के लिए Arrows |
उदाहरण के लिए:
runST :: (forall s. ST s a) -> a
बन जाएगा
runST ∷ (∀ s. ST s a) → a
ध्यान दें कि *
बनाम ★
उदाहरण थोड़ा अलग है: क्योंकि *
आरक्षित नहीं है, ★
भी गुणा, या किसी अन्य फ़ंक्शन नाम (*)
, और इसके विपरीत के रूप में *
उसी तरह काम करता है। उदाहरण के लिए:
ghci> 2 ★ 3
6
ghci> let (*) = (+) in 2 ★ 3
5
ghci> let (★) = (-) in 2 * 3
-1
BinaryLiterals
स्टैंडर्ड हास्केल आपको दशमलव (पूर्णांक के बिना) में पूर्णांक शाब्दिक लिखने की अनुमति देता है, हेक्साडेसिमल ( 0x
या 0X
से पहले), और ऑक्टल ( 0o
या 0O
द्वारा पूर्ववर्ती)। BinaryLiterals
विस्तार द्विआधारी का विकल्प (से पहले कहते हैं 0b
या 0B
)।
0b1111 == 15 -- evaluates to: True
ExistentialQuantification
यह एक प्रकार प्रणाली विस्तार है जो प्रकार है कि existentially मात्रा निर्धारित कर रहे हैं, या दूसरे शब्दों में अनुमति देता है, प्रकार चर है कि केवल रनटाइम पर instantiated हो † है।
अस्तित्वगत प्रकार का एक मान OO भाषाओं में एक अमूर्त-बेस-क्लास संदर्भ के समान है: आप इसमें सटीक प्रकार नहीं जानते हैं, लेकिन आप प्रकारों के वर्ग को बाधित कर सकते हैं।
data S = forall a. Show a => S a
या समकक्ष, GADT सिंटैक्स के साथ:
{-# LANGUAGE GADTs #-}
data S where
S :: Show a => a -> S
अस्तित्ववादी प्रकार लगभग-विषम कंटेनरों जैसी चीजों के लिए दरवाजा खोलते हैं: जैसा कि ऊपर कहा गया है, वास्तव में एक S
मूल्य में विभिन्न प्रकार हो सकते हैं, लेकिन उनमें से सभी को एन show
जा सकता है, इसलिए आप भी कर सकते हैं
instance Show S where
show (S a) = show a -- we rely on (Show a) from the above
अब हम ऐसी वस्तुओं का संग्रह बना सकते हैं:
ss = [S 5, S "test", S 3.0]
जो हमें बहुरूपी व्यवहार का उपयोग करने की भी अनुमति देता है:
mapM_ print ss
अस्तित्व बहुत शक्तिशाली हो सकते हैं, लेकिन ध्यान दें कि वे वास्तव में हास्केल में बहुत बार आवश्यक नहीं हैं। उपरोक्त उदाहरण में, आप वास्तव में Show
उदाहरण के साथ कर सकते हैं शो (duh!) मान है, अर्थात एक स्ट्रिंग प्रतिनिधित्व बनाएँ। पूरे S
प्रकार में वास्तव में उतनी ही जानकारी होती है जितनी कि स्ट्रिंग आपको दिखाते समय मिलती है। इसलिए, आमतौर पर उस स्ट्रिंग को तुरंत स्टोर करना बेहतर होता है, खासकर जब से हास्केल आलसी होता है और इसलिए पहले से ही स्ट्रिंग वैसे भी केवल एक अनवैलिड थंक होगा।
दूसरी ओर, अस्तित्ववादी कुछ अनोखी समस्याएं पैदा करते हैं। उदाहरण के लिए, प्रकार की जानकारी एक अस्तित्व में "छिपी" है। यदि आप S
मान पर प्रतिमान-मिलान करते हैं, तो आपके पास समाहित प्रकार का दायरा होगा (अधिक सटीक रूप से, इसका उदाहरण Show
), लेकिन यह जानकारी कभी भी इसके दायरे से बच नहीं सकती है, इसलिए यह "गुप्त समाज" का एक सा बन जाता है: संकलक उन मानों को छोड़ कर कुछ भी नहीं होने देता है , जिनके प्रकार पहले से ही बाहर से ज्ञात हैं। यह अजीब त्रुटियों को जन्म दे सकता है जैसे कि Couldn't match type 'a0' with '()' 'a0' is untouchable
।
Ric इसके विपरीत साधारण पैरामीट्रिक बहुरूपता है, जो आम तौर पर संकलन समय (पूर्ण प्रकार के उन्मूलन की अनुमति) में हल किया जाता है।
अस्तित्व-प्रकार रैंक-एन प्रकार से भिन्न होते हैं - ये एक्सटेंशन हैं, मोटे तौर पर बोल, एक दूसरे से दोहरे: वास्तव में एक अस्तित्वगत प्रकार के मूल्यों का उपयोग करने के लिए, आपको उदाहरण में show
के लिए एक (संभवतः विवश-) बहुरूपिक फ़ंक्शन की आवश्यकता होती है। एक पॉलीमॉर्फिक फ़ंक्शन सार्वभौमिक रूप से परिमाणित है, अर्थात यह किसी दिए गए वर्ग में किसी भी प्रकार के लिए काम करता है, जबकि अस्तित्वगत मात्रा का मतलब है कि यह कुछ विशेष प्रकार के लिए काम करता है जो कि एक प्राथमिक अज्ञात है। यदि आपके पास एक बहुरूपी कार्य है, तो यह पर्याप्त है, हालांकि {-# LANGUAGE Rank2Types #-}
कार्यों जैसे कि तर्कों को पारित करने के लिए, आपको {-# LANGUAGE Rank2Types #-}
: की आवश्यकता है।
genShowSs :: (∀ x . Show x => x -> String) -> [S] -> [String]
genShowSs f = map (\(S a) -> f a)
LambdaCase
एक वाक्यात्मक विस्तार जो आपको \arg -> case arg of
स्थान पर \arg -> case arg of
\case
लिखने देता \arg -> case arg of
।
निम्नलिखित फ़ंक्शन परिभाषा पर विचार करें:
dayOfTheWeek :: Int -> String
dayOfTheWeek 0 = "Sunday"
dayOfTheWeek 1 = "Monday"
dayOfTheWeek 2 = "Tuesday"
dayOfTheWeek 3 = "Wednesday"
dayOfTheWeek 4 = "Thursday"
dayOfTheWeek 5 = "Friday"
dayOfTheWeek 6 = "Saturday"
यदि आप फ़ंक्शन का नाम दोहराने से बचना चाहते हैं, तो आप कुछ ऐसा लिख सकते हैं:
dayOfTheWeek :: Int -> String
dayOfTheWeek i = case i of
0 -> "Sunday"
1 -> "Monday"
2 -> "Tuesday"
3 -> "Wednesday"
4 -> "Thursday"
5 -> "Friday"
6 -> "Saturday"
लेम्बडाकैस एक्सटेंशन का उपयोग करते हुए, आप तर्क को नाम दिए बिना फ़ंक्शन अभिव्यक्ति के रूप में लिख सकते हैं:
{-# LANGUAGE LambdaCase #-}
dayOfTheWeek :: Int -> String
dayOfTheWeek = \case
0 -> "Sunday"
1 -> "Monday"
2 -> "Tuesday"
3 -> "Wednesday"
4 -> "Thursday"
5 -> "Friday"
6 -> "Saturday"
RankNTypes
निम्नलिखित स्थिति की कल्पना करें:
foo :: Show a => (a -> String) -> String -> Int -> IO ()
foo show' string int = do
putStrLn (show' string)
putStrLn (show' int)
यहां, हम एक फ़ंक्शन में पास करना चाहते हैं जो एक मान को स्ट्रिंग में परिवर्तित करता है, उस फ़ंक्शन को एक स्ट्रिंग पैरामीटर और इंट पैरामीटर दोनों पर लागू करें और उन दोनों को प्रिंट करें। मेरे दिमाग में, कोई कारण नहीं है कि यह विफल होना चाहिए! हमारे पास एक फ़ंक्शन है जो दोनों प्रकार के मापदंडों पर काम करता है जो हम पास कर रहे हैं।
दुर्भाग्य से, यह चेक टाइप नहीं करेगा! जीएचसी फ़ंक्शन बॉडी में अपनी पहली घटना के आधार पर a
प्रकार को संक्रमित करता है। जैसे ही, हमने मारा:
putStrLn (show' string)
जीएचसी वह show' :: String -> String
, चूंकि string
एक String
। यह show' int
कोशिश करते हुए आगे बढ़ना होगा।
RankNTypes
आपको निम्न प्रकार के हस्ताक्षर लिखने के बजाय, show'
प्रकार को संतुष्ट करने वाले सभी कार्यों पर निर्भर करता है:
foo :: (forall a. Show a => (a -> String)) -> String -> Int -> IO ()
यह रैंक 2 बहुरूपता है: हम जोर देते हुए कर रहे हैं कि show'
सभी के लिए समारोह होगा काम a
हमारे समारोह के भीतर है, और पिछले कार्यान्वयन अब काम करता है।
RankNTypes
एक्सटेंशन, RankNTypes
मनमाने तरीके से घोंसले के शिकार की अनुमति देता है forall ...
प्रकार के हस्ताक्षर में ब्लॉक। दूसरे शब्दों में, यह रैंक एन बहुरूपता की अनुमति देता है।
OverloadedLists
जीएचसी 7.8 में जोड़ा गया ।
OverloadedLists, के समान OverloadedStrings , की अनुमति देता है के रूप में इस सूची शाब्दिक desugared जा करने के लिए:
[] -- fromListN 0 []
[x] -- fromListN 1 (x : [])
[x .. ] -- fromList (enumFrom x)
यह Set
, Vector
और Map
जैसे प्रकारों के साथ काम करते समय काम आता है।
['0' .. '9'] :: Set Char
[1 .. 10] :: Vector Int
[("default",0), (k1,v1)] :: Map String Int
['a' .. 'z'] :: Text
इस विस्तार के साथ GHC.Exts
में IsList
वर्ग का उपयोग करने का इरादा है।
IsList
एक प्रकार के फ़ंक्शन, Item
और तीन कार्यों से सुसज्जित है, fromList :: [Item l] -> l
, toList :: l -> [Item l]
और fromListN :: Int -> [Item l] -> l
जहाँ fromListN
वैकल्पिक है। विशिष्ट कार्यान्वयन हैं:
instance IsList [a] where
type Item [a] = a
fromList = id
toList = id
instance (Ord a) => IsList (Set a) where
type Item (Set a) = a
fromList = Set.fromList
toList = Set.toList
ओवरलोडेडलिस्ट्स से लिए गए उदाहरण - जीएचसी ।
FunctionalDependencies
यदि आपके पास a, b, c, और x के साथ मल्टी-पैरामीटर टाइप-क्लास है, तो यह एक्सटेंशन आपको यह व्यक्त करने देता है कि टाइप x को विशिष्ट रूप से a, b और c से पहचाना जा सकता है:
class SomeClass a b c x | a b c -> x where ...
इस तरह के वर्ग की एक आवृत्ति की घोषणा करते समय, यह सुनिश्चित करने के लिए अन्य सभी उदाहरणों के खिलाफ जाँच की जाएगी कि कार्यात्मक निर्भरता रखती है, अर्थात समान abc
साथ कोई अन्य उदाहरण नहीं है, लेकिन अलग-अलग x
मौजूद हैं।
आप अल्पविराम से अलग की गई सूची में कई निर्भरताएँ निर्दिष्ट कर सकते हैं:
class OtherClass a b c d | a b -> c d, a d -> b where ...
एमटीएल में उदाहरण के लिए हम देख सकते हैं:
class MonadReader r m| m -> r where ...
instance MonadReader r ((->) r) where ...
अब, यदि आपके पास प्रकार का मान है MonadReader a ((->) Foo) => a
, संकलक अनुमान लगा सकता है कि a ~ Foo
, क्योंकि दूसरा तर्क पूरी तरह से पहले को निर्धारित करता है, और तदनुसार प्रकार को सरल करेगा।
SomeClass
वर्ग तर्कों के एक समारोह के रूप में सोचा जा सकता abc
कि में परिणाम x
। इस तरह की कक्षाओं का उपयोग टाइपसिस्टम में कम्प्यूटेशन करने के लिए किया जा सकता है।
GADTs
परम्परागत बीजगणितीय डेटाेटिप्स उनके प्रकार चर में पैरामीट्रिक हैं। उदाहरण के लिए, यदि हम ADT को परिभाषित करते हैं
data Expr a = IntLit Int
| BoolLit Bool
| If (Expr Bool) (Expr a) (Expr a)
इस उम्मीद के साथ कि यह गैर-अच्छी तरह से टाइप किए गए सशर्त नियमों का पालन करेगा, यह IntLit :: Int -> Expr a
के प्रकार के बाद से अपेक्षित व्यवहार नहीं करेगा IntLit :: Int -> Expr a
रूप से निर्धारित है: किसी भी विकल्प के a
, यह प्रकार का एक मान पैदा करता है Expr a
। विशेष रूप से, के लिए a ~ Bool
, हमारे पास IntLit :: Int -> Expr Bool
हमें की तरह कुछ का निर्माण करने की अनुमति देता है, If (IntLit 1) e1 e2
है जो के प्रकार के If
निर्माता से इनकार करने के लिए कोशिश कर रहा था।
सामान्यीकृत बीजीय डेटा प्रकार हमें डेटा निर्माता के परिणामी प्रकार को नियंत्रित करने की अनुमति देता है ताकि वे केवल पैरामीट्रिक न हों। हम अपने Expr
प्रकार को इस तरह GADT के रूप में फिर से लिख सकते हैं:
data Expr a where
IntLit :: Int -> Expr Int
BoolLit :: Bool -> Expr Bool
If :: Expr Bool -> Expr a -> Expr a -> Expr a
यहां, कंस्ट्रक्टर IntLit
का प्रकार Int -> Expr Int
, और इसलिए IntLit 1 :: Expr Bool
टाइपकास्ट नहीं होगा।
एक जीएडीटी मूल्य पर पैटर्न का मिलान लौटे हुए शब्द के प्रकार को परिष्कृत करता है। उदाहरण के लिए, Expr a
लिए मूल्यांकनकर्ता को इस तरह लिखना संभव है:
crazyEval :: Expr a -> a
crazyEval (IntLit x) =
-- Here we can use `(+)` because x :: Int
x + 1
crazyEval (BoolLit b) =
-- Here we can use `not` because b :: Bool
not b
crazyEval (If b thn els) =
-- Because b :: Expr Bool, we can use `crazyEval b :: Bool`.
-- Also, because thn :: Expr a and els :: Expr a, we can pass either to
-- the recursive call to `crazyEval` and get an a back
crazyEval $ if crazyEval b then thn else els
ध्यान दें कि हम उपरोक्त परिभाषाओं में (+)
का उपयोग करने में सक्षम हैं क्योंकि जब IntLit x
पैटर्न से मेल खाता है, तो हम यह भी सीखते हैं कि a ~ Int
(इसी तरह not
और if_then_else_
जब a ~ Bool
)।
ScopedTypeVariables
ScopedTypeVariables
आपको घोषणा के अंदर सार्वभौमिक रूप से मात्रात्मक प्रकारों को संदर्भित करते हैं। अधिक स्पष्ट होना:
import Data.Monoid
foo :: forall a b c. (Monoid b, Monoid c) => (a, b, c) -> (b, c) -> (a, b, c)
foo (a, b, c) (b', c') = (a :: a, b'', c'')
where (b'', c'') = (b <> b', c <> c') :: (b, c)
महत्वपूर्ण बात यह है कि हम का उपयोग कर सकते है a
, b
और c
के लिए संकलक हिदायत घोषणा के subexpressions में (टपल में where
खंड और पहले a
अंतिम परिणाम में)। व्यवहार में, ScopedTypeVariables
जटिल कार्यों को भागों के योग के रूप में लिखने में सहायता करते हैं, जिससे प्रोग्रामर को मध्यवर्ती मानों के लिए टाइप हस्ताक्षर जोड़ने की अनुमति मिलती है जिसमें ठोस प्रकार नहीं होते हैं।
PatternSynonyms
पैटर्न समानार्थक शब्द के समान पैटर्न के सार हैं कैसे फ़ंक्शन अभिव्यक्ति के सार हैं।
इस उदाहरण के लिए, आइए इंटरफेस Data.Sequence
को देखें, और देखते हैं कि पैटर्न समानार्थक शब्द के साथ इसे कैसे बेहतर बनाया जा सकता है। Seq
प्रकार एक डेटा प्रकार है, जो आंतरिक रूप से, विभिन्न परिचालनों के लिए अच्छी स्पर्शोन्मुख जटिलता को प्राप्त करने के लिए एक जटिल प्रतिनिधित्व का उपयोग करता है, विशेष रूप से O (1) (un) कंसिंग और (un) स्नोकिंग दोनों।
लेकिन यह प्रतिनिधित्व नाकाफी है और हास्केल के प्रकार प्रणाली में इसके कुछ अपरिवर्तनों को व्यक्त नहीं किया जा सकता है। इसके कारण, Seq
प्रकार उपयोगकर्ताओं के बीच एक अमूर्त प्रकार के रूप में प्रकट होता है, साथ ही साथ इनवेरिएंट-प्रोटेक्टिंग एक्सेसर और कंस्ट्रक्टर फ़ंक्शंस:
empty :: Seq a
(<|) :: a -> Seq a -> Seq a
data ViewL a = EmptyL | a :< (Seq a)
viewl :: Seq a -> ViewL a
(|>) :: Seq a -> a -> Seq a
data ViewR a = EmptyR | (Seq a) :> a
viewr :: Seq a -> ViewR a
लेकिन इस इंटरफ़ेस का उपयोग करना थोड़ा बोझिल हो सकता है:
uncons :: Seq a -> Maybe (a, Seq a)
uncons xs = case viewl xs of
x :< xs' -> Just (x, xs')
EmptyL -> Nothing
हम कुछ हद तक इसे साफ करने के लिए व्यू पैटर्न का उपयोग कर सकते हैं:
{-# LANGUAGE ViewPatterns #-}
uncons :: Seq a -> Maybe (a, Seq a)
uncons (viewl -> x :< xs) = Just (x, xs)
uncons _ = Nothing
PatternSynonyms
भाषा के विस्तार का उपयोग करते हुए, हम पैटर्न को मेल खाने की अनुमति देकर एक समीपवर्ती इंटरफ़ेस दे सकते हैं कि हमारे पास एक कंसोल या स्नोक-सूची है:
{-# LANGUAGE PatternSynonyms #-}
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
pattern Empty :: Seq a
pattern Empty <- (Seq.viewl -> Seq.EmptyL)
pattern (:<) :: a -> Seq a -> Seq a
pattern x :< xs <- (Seq.viewl -> x Seq.:< xs)
pattern (:>) :: Seq a -> a -> Seq a
pattern xs :> x <- (Seq.viewr -> xs Seq.:> x)
यह हमें बहुत ही प्राकृतिक शैली में uncons
लिखने की अनुमति देता है:
uncons :: Seq a -> Maybe (a, Seq a)
uncons (x :< xs) = Just (x, xs)
uncons _ = Nothing
RecordWildCards
RecordWildCards देखें