हास्केल में गोल्फ के लिए टिप्स


73

हास्केल में गोल्फ के लिए आपके पास क्या सामान्य सुझाव हैं? मैं उन विचारों की तलाश कर रहा हूं, जो सामान्य रूप से कोड समस्याओं को लागू कर सकते हैं जो कम से कम कुछ हद तक हास्केल के लिए विशिष्ट हैं। कृपया प्रति उत्तर केवल एक टिप पोस्ट करें।


यदि आप हास्केल में गोल्फ के लिए नए हैं, तो कृपया हास्केल में गाइड टू गोल्फिंग नियमों पर एक नज़र डालें । एक समर्पित हास्केल चैट रूम भी है: मोनाड्स और पुरुषों का


1
अब तक के जवाबों की संख्या देखकर, मुझे संदेह है कि हास्केल कोड गोल्फिंग के लिए एक अच्छी भाषा है या नहीं?
अनिमेष 'CODER'

10
प्रति उत्तर केवल एक टिप क्यों? साथ ही, हर भाषा गोल्फ के लिए एक अच्छी भाषा है। बस हमेशा जीतने की उम्मीद मत करो।
चाचा

6
@unclemeat इस तरह से लोग अच्छे लोगों को ऊपर तक ले जा सकते हैं, केवल बुरे लोगों को अपवित्र किए बिना क्योंकि वे एक ही आदमी द्वारा एक ही उत्तर में लिखे गए थे।
MasterMastic

3
विशेष अनुरोध, स्ट्रिंग संपीड़न।
जे एटकिन

यह शायद एवर के
liners

जवाबों:


45

बाइनरी फ़ंक्शंस के बजाय इन्फिक्स ऑपरेटरों को परिभाषित करें

यह आमतौर पर प्रति परिभाषा या कॉल में एक या दो स्थान बचाता है।

0!(y:_)=y
x!(y:z)=(x-1)!z

बनाम

f 0(y:_)=y
f x(y:z)=f(x-1)z

1-बाइट ऑपरेटरों के लिए उपलब्ध प्रतीक हैं !, #, %, &, और ?। अन्य सभी ASCII विराम चिह्न को या तो पहले से ही एक ऑपरेटर के रूप में परिभाषित किया गया है (जैसे $) या हास्केल के सिंटैक्स में एक विशेष अर्थ है (जैसे @)।

यदि आपको पांच से अधिक ऑपरेटरों की आवश्यकता है, तो आप उपरोक्त संयोजनों का उपयोग कर सकते हैं, जैसे कि !#, या कुछ यूनिकोड विराम चिह्न वर्ण, जैसे कि ये (UTF-8 में सभी 2 बाइट्स):

¡ ¢ £ ¤ ¥ ¦ § ¨ © ¬ ® ¯ ° ± ´ ¶ · ¸ ¿ × ÷

11
नोट: इसका उपयोग तीन या अधिक तर्कों वाले कार्यों के लिए भी किया जा सकता है। (x!y)z=x+y*zऔर (x#y)z u=x*z+y*uदोनों उम्मीद के मुताबिक काम करते हैं।
जरगब

3
इसका उपयोग फ़ंक्शन तर्कों के लिए भी किया जा सकता है, उदाहरण \f g(!)x y->f g!x yके लिए\f g j x y->j(f g)(x y)
Esolanging Fruit

2
कभी-कभी यदि आप अन्यथा कोष्ठक का उपयोग करना चाहते हैं, तो बाइनरी ऑपरेटरों के लिए यूनिरी फ़ंक्शंस को बदलना फायदेमंद g x=…;g(f x)होता है_?x=…;0!f x
इससे

29

जहाँ उपयुक्त हो, वहाँ व्यर्थ (या मुक्त) अंकन का उपयोग करें

अक्सर एक या दो मापदंडों के साथ एक फ़ंक्शन को बिंदु मुक्त लिखा जा सकता है।

इसलिए उन तत्वों की सूची की खोज की जा रही है जिनके तत्वों की अदला-बदली की गई है:

revlookup :: Eq b => b -> [(a, b)] -> Maybe a
revlookup e l=lookup e(map swap l)

(प्रकार केवल यह समझने में आपकी सहायता करने के लिए है कि यह क्या कर रहा है।)

हमारे उद्देश्यों के लिए यह बहुत बेहतर है:

revlookup=(.map swap).lookup

28

सूची का उपयोग करें

एक त्वरित समीक्षा:

xs >> ys        =  concat $ replicate (length xs) ys
xs >>= f        =  concatMap f xs
mapM id[a,b,c]  =  cartesian product of lists: a × b × c
mapM f[a,b,c]   =  cartesian product of lists: f a × f b × f c

उदाहरण:

  • एक सूची को दो बार दोहराना

    Prelude> "aa">>[1..5]
    [1,2,3,4,5,1,2,3,4,5]
    
  • छोटा concatMap

    Prelude> reverse=<<["Abc","Defgh","Ijkl"]
    "cbAhgfeDlkjI"
    
  • कम concat+ सूची समझ

    Prelude> do x<-[1..5];[1..x]
    [1,1,2,1,2,3,1,2,3,4,1,2,3,4,5]
    
  • कार्तीय गुणन

    Prelude> mapM id["Hh","io",".!"]
    ["Hi.","Hi!","Ho.","Ho!","hi.","hi!","ho.","ho!"]
    
  • एक जाली पर निर्देशांक की सूची

    Prelude> mapM(\x->[0..x])[3,2]
    [[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2],[3,0],[3,1],[3,2]]
    

1
मैं [0..b]>>[a]इसके बजाय उपयोगी पाया गया है replicate a b
गेहूं जादूगर

3
@WheatWizard a<$[1..b]और भी छोटा है, के लिए replicate
लिन

=<<आयात करने के लिए बल का उपयोग करना Control.Monad। यदि आपको किसी अन्य कारण से तर्क की अदला-बदली नहीं करनी है और उपयोग करना >>=अधिक संक्षिप्त लगता है।
18

OTOH, यदि आपको किसी Data.Traversableभी तरह की जरूरत है, तो कार्टेसियन उत्पाद उदाहरण को छोटा किया जा सकता है for["Hh","io",".!"]id
18

2
(=<<)वास्तव में , प्रस्तावना में है! मैंने इसका भरपूर उपयोग किया है।
लिन

28

सशर्त नहीं गार्ड का उपयोग करें:

f a=if a>0 then 3 else 7
g a|a>0=3|True=7

अर्धवृत्तों का उपयोग करें जो इंडेंट नहीं हैं

f a=do
  this
  that
g a=do this;that

बूलियन कार्यों के लिए बूलियन अभिव्यक्तियों का उपयोग करें

f a=if zzz then True else f yyy
g a=zzz||f yyy

(एसओ को मुझे अलग से पोस्ट करने देने के बारे में दर्द हो रहा है)


2
इसके अलावा, &&जब एक सूची समझ के अंदर कई गार्ड का उपयोग करें ।
जॉन ड्वोरक

अच्छा एक जनवरी - आपको इसे एक उत्तर में बनाना चाहिए, मैं इसके लिए वोट
करूंगा

5
पहला उदाहरण आगे True=> द्वारा संक्षिप्त किया जा सकता है1>0
जॉन ड्वोरक

1
पहले उदाहरण में, मेरा मतलब है कि आपf a=if a>0 then 3 else 7
साइओस

अगर इसमें कोई तर्क नहीं है तो गार्ड भी काम करता है।
अकांगका

24

interact :: (String → String) → IO ()

लोग अक्सर यह भूल जाते हैं कि यह फ़ंक्शन मौजूद है - यह सभी स्टड को पकड़ लेता है और इसे एक (शुद्ध) फ़ंक्शन पर लागू करता है। मैं अक्सर mainकी तर्ज पर -कोड देखता हूं

main=getContents>>=print.foo

जबकि

main=interact$show.foo

काफी छोटा है। यह प्रस्ताव में है इसलिए आयात की कोई आवश्यकता नहीं है!


24

जीएचसी 7.10 का उपयोग करें

GHC का पहला संस्करण जिसमें यह सामान शामिल था , 27 मार्च 2015 को जारी किया गया था ।

यह नवीनतम संस्करण है, और प्रील्यूड को कुछ नए अतिरिक्त मिले हैं जो गोल्फ के लिए उपयोगी हैं:

(<$>)और (<*>)ऑपरेटरों

इन उपयोगी ऑपरेटरों से Data.Applicativeइसे बनाया है! <$>बस है fmapतो आप की जगह ले सकता, map f xऔर fmap f xसाथ f<$>xहर जगह है और वापस बाइट्स जीतने के लिए। इसके अलावा, सूचियों के लिए उदाहरण <*>में उपयोगी है Applicative:

Prelude> (,)<$>[1..2]<*>"abcd"
[(1,'a'),(1,'b'),(1,'c'),(1,'d'),(2,'a'),(2,'b'),(2,'c'),(2,'d')]

(<$)ऑपरेटर

x<$aके बराबर है fmap (const x) a; यानी हर तत्व को कंटेनर में बदल दिया जाता है x

यह अक्सर एक अच्छा विकल्प है replicate: 4<$[1..n]की तुलना में कम है replicate n 4

फोल्डेबल / ट्रैवर्सेबल प्रस्ताव

निम्नलिखित कार्यों को सूचियों पर काम करने से उठाकर [a]सामान्य Foldableप्रकारों में लाया गया t a:

fold*, null, length, elem, maximum, minimum, sum, product
and, or, any, all, concat, concatMap

इसका मतलब है कि वे अब भी काम करते हैं Maybe a, जहां वे "सबसे अधिक एक तत्व के साथ सूचीबद्ध" की तरह व्यवहार करते हैं। उदाहरण के लिए, null Nothing == Trueया sum (Just 3) == 3। इसी तरह, मानों के लिए length0 Nothingऔर 1 रिटर्न Just। लिखने के बजाय x==Just yआप लिख सकते हैं elem y x

आप उन्हें टुपल्स पर भी लागू कर सकते हैं, जो काम करता है जैसे कि आपने \(a, b) -> [b]पहले फोन किया था। यह लगभग पूरी तरह से बेकार है, लेकिन or :: (a, Bool) -> Boolएक चरित्र की तुलना में छोटा है snd, और इससे elem bछोटा है (==b).snd

द मोनॉयड फ़ंक्शंस memptyऔरmappend

अक्सर जीवन रक्षक नहीं होता है, लेकिन यदि आप टाइप कर सकते हैं, memptyतो एक बाइट से कम है Nothing, इसलिए ऐसा है।


5
+1 '<$>' के बारे में सुनना और <*>उसे प्रस्तावना में बनाना बहुत अच्छा है! यह तब भी उपयोगी होना चाहिए जब यह कोड गोल्फ न हो (अनुप्रयोग इतना लंबा शब्द है)।
आख-मोर्पर्क

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

4
मजेदार है [1..2]वहां। बस इतना है[1,2]
गर्व हैकेकलर

2
एक ही संस्करण में हम भी मिल गया <*से Applicativeसूचियों के लिए है जो, xs <* ys == concatMap (replicate (length ys)) xs। यह अलग है xs >> ysया xs *> ysजो है concat (replicate (length ys)) xspureजो छोटा है returnवह इस बिंदु पर भी आया।
एंग्स

2
आप अब के <>बजाय का उपयोग कर सकते हैं mappend, यह अब (जीएचसी 8.4.1 के साथ) का हिस्सा है Prelude

22

के 1<2बजाय Trueऔर के 1>2बजाय का उपयोग करें False

g x|x<10=10|True=x
f x|x<10=10|1<2=x

3
यह हास्केल के लिए वास्तव में विशिष्ट नहीं है: यह सिर्फ हर भाषा के बारे में लागू होता है जिसमें एक बूलियन प्रकार होता है जो अन्य प्रकारों के सत्य और झूठे मूल्यों के विपरीत होता है।
पीटर टेलर

क्या कोई इसे समझा सकता है?
MasterMastic

2
यह एक अच्छा उदाहरण नहीं है, मैं सिर्फ इस के रूप में गोल्फ होगा f=max 10
गर्वित हैकेलर

@MasterMastic यह सिर्फ if(true)अन्य भाषाओं में लिख रहा है। प्रस्तावना में, अन्यथा वास्तव में बूलियन मूल्य है True
गर्वित हैकेलर

2
@PeterTaylor मुझे लगता है कि यह नए हैस्केलियंस (मेरे जैसे) के लिए अभी भी मूल्यवान है जैसा कि मैंने पहली बार उपयोग करना सीखा otherwise
दोष

20

सूची समझ का उपयोग करें (चतुर तरीके से)

हर कोई जानता है कि वे उपयोगी वाक्यविन्यास हैं, अक्सर mapएक मेमने से कम :

Prelude> [[1..x]>>show x|x<-[1..9]]
["1","22","333","4444","55555","666666","7777777","88888888","999999999"]

या filter(वैकल्पिक रूप से एक mapही समय में):

Prelude> [show x|x<-[1..60],mod 60x<1]
["1","2","3","4","5","6","10","12","15","20","30","60"]

लेकिन कुछ वेइडर उपयोग हैं जो अभी और फिर काम में आते हैं। एक के लिए, एक सूची समझ के लिए किसी भी <-तीर को शामिल करने की आवश्यकता नहीं है :

Prelude> [1|False]
[]
Prelude> [1|True]
[1]

जिसके बजाय if p then[x]else[]आप लिख सकते हैं [x|p]। इसके अलावा, किसी शर्त को संतुष्ट करने वाली सूची के तत्वों की संख्या की गणना करने के लिए, सहज रूप से आप लिखेंगे:

length$filter p x

लेकिन यह छोटा है:

sum[1|y<-x,p y]

मैंने वास्तव में इन सभी का पहले इस्तेमाल किया था, लेकिन मैंने उन्हें यहां रखने के लिए नहीं सोचा था।
गर्वित हैकेलर

18

पता है आपकी Prelude

GHCi को फायर करें और प्रस्तावना प्रलेखन के माध्यम से स्क्रॉल करें । जब भी आप किसी फ़ंक्शन का संक्षिप्त नाम पार करते हैं, तो यह कुछ मामलों की तलाश के लिए भुगतान कर सकता है जहां यह उपयोगी हो सकता है।

उदाहरण के लिए, यदि आप एक स्ट्रिंग को बदलने के लिए चाहते हैं लगता है s = "abc\ndef\nghi", एक अंतरिक्ष से अलग की गई है कि में "abc def ghi"। स्पष्ट तरीका है:

unwords$lines s

लेकिन आप बेहतर कर सकते हैं यदि आप दुरुपयोग करते हैं max, और यह तथ्य कि \n < space < printable ASCII:

max ' '<$>s

एक और उदाहरण है lex :: String -> [(String, String)], जो कुछ रहस्यमय तरीके से करता है:

Prelude> lex "   some string of Haskell tokens  123  "
[("some"," string of Haskell tokens  123  ")]

व्हाट्सएप fst=<<lex sको स्किप करते हुए एक स्ट्रिंग से पहला टोकन प्राप्त करने का प्रयास करें । मानों पर उपयोग करने वाली हेन्कमा द्वारा यहां एक चतुर समाधान है ।lex.showRational


16

एक स्थिर मान का मिलान करें

एक सूची समझ एक स्थिर पर मेल खा सकती है।


[0|0<-l]

यह एक सूची के 0 को निकालता है l, यानी कि 0 की सूची बनाता है जो कि अंदर हैं l


[1|[]<-f<$>l] 

यह के रूप में कई की एक सूची बनाता है 1के रूप में वहाँ के तत्व हैं की lहै कि f(का उपयोग कर खाली सूची पर ले जाता है <$>इन्फ़िक्स के रूप में map)। sumइन तत्वों को गिनने के लिए आवेदन करें ।

की तुलना करें:

[1|[]<-f<$>l]
[1|x<-l,f x==[]]

[x|(0,x)<-l]

एक पैटर्न पैटर्न के भाग के रूप में एक स्थिरांक का उपयोग किया जा सकता है। यह उन सभी tuples की दूसरी प्रविष्टियों को निकालता है जिनकी पहली प्रविष्टि है 0


ध्यान दें कि इन सभी के लिए एक वास्तविक स्थिर शाब्दिक की आवश्यकता होती है, किसी चर के मूल्य की नहीं। उदाहरण के लिए, let x=1 in [1|x<-[1,2,3]]आउटपुट होगा [1,1,1], नहीं [1], क्योंकि बाहरी xबाध्यकारी ओवरराइट किया गया है।


14

wordsतार की लंबी सूची के बजाय उपयोग करें । यह वास्तव में हास्केल के लिए विशिष्ट नहीं है, अन्य भाषाओं में भी समान चालें हैं।

["foo","bar"]
words"foo bar"  -- 1 byte longer
["foo","bar","baz"]
words"foo bar baz"  -- 1 byte shorter
["foo","bar","baz","qux"]
words"foo bar baz qux"    -- 3 bytes shorter

14

अपने राक्षसी कार्यों को जानें

1)
का उपयोग कर विवादास्पद कार्यों का अनुकरण mapM

कई बार कोड होगा sequence(map f xs), लेकिन इसे प्रतिस्थापित किया जा सकता है mapM f xs। यहां तक ​​कि जब सिर्फ sequenceअकेले का उपयोग कर यह लंबे समय तक है mapM id

2)
का उपयोग कर (>>=)(या (=<<)) गठबंधन कार्यों

फ़ंक्शन का मानद संस्करण निम्नानुसार (>>=)परिभाषित किया गया है:

(f >>= g) x = g (f x) x 

यह उन कार्यों को बनाने के लिए उपयोगी हो सकता है जिन्हें पाइपलाइन के रूप में व्यक्त नहीं किया जा सकता है। उदाहरण के लिए, \x->x==nub xसे अधिक लंबा है nub>>=(==), और इससे \t->zip(tail t)tअधिक लंबा है tail>>=zip


+1 - मुझे यह भी एहसास नहीं था कि कार्यों के लिए एक सनक उदाहरण था। यह बहुत आसान हो सकता है :)
जूल्स

2
साइड नोट: हालांकि इसका हिस्सा है Applicativeऔर Monadइसके कार्यान्वयन के pureरूप में अच्छी तरह से नहीं है जो इससे छोटा है constऔर वास्तव में इससे पहले मेरी मदद की है।
19

14

तर्क परिभाषाओं से कम हो सकते हैं

मैं अभी बहुत उत्सुक तरीके से बाहर निकला हेंकमा बहक गया

यदि fआपके उत्तर में एक सहायक फ़ंक्शन एक ऑपरेटर का उपयोग करता है जो आपके उत्तर में कहीं और उपयोग नहीं किया जाता है, औरf एक बार कॉल किया जाता है, तो ऑपरेटर को एक तर्क दें f

इस:

(!)=take
f a=5!a++3!a
reverse.f

क्या दो बाइट्स इससे अधिक हैं:

f(!)a=5!a++3!a
reverse.f take

12

विपक्ष ऑपरेटर का उपयोग करें (:)

जब समवर्ती सूची, पहली लंबाई 1 की है तो :इसके बजाय का उपयोग करें ।

a++" "++b
a++' ':b  -- one character shorter

[3]++l
3:l    -- three characters shorter

4
यह देखते हुए कि यह सही साहचर्य है, तो आप सूची की शुरुआत है, जैसे में एकल आइटम के किसी भी संख्या के लिए उपयोग रख सकते वर्थ 1:2:3:xके बजाय [1,2,3]++x
जूल्स

11

बहुत बार backticks का उपयोग न करें। बैकस्टिक्स उपसर्ग कार्यों के अनुभाग बनाने के लिए एक अच्छा उपकरण है, लेकिन कभी-कभी इसका दुरुपयोग किया जा सकता है।

एक बार जब मैंने देखा कि कोई व्यक्ति इस उपप्रकार को लिखता है:

(x`v`)

हालांकि यह बस के रूप में ही है v x

एक अन्य उदाहरण के (x+1)`div`y रूप में लिख रहा है div(x+1)y

मैं देखता हूं कि यह चारों ओर divऔर elemअधिक बार होता है क्योंकि इन कार्यों को आमतौर पर नियमित कोड में इन्फिक्स के रूप में उपयोग किया जाता है।


क्या आपका मतलब उपसर्ग कार्यों के अनुभाग बनाने से नहीं है ?
साइओस

@Cyoce हां, निश्चित रूप से
गर्वित हैकेलर

11

पैटर्न गार्ड का उपयोग करें

वे letएक लैम्बडा से छोटे हैं जो आपके द्वारा परिभाषित किसी फ़ंक्शन के तर्कों को डिक्रिप्ट करता है। यह मदद करता है जब आप fromJustसे कुछ की जरूरत है Data.Maybe:

f x=let Just c=… in c

से लंबा है

f x=(\(Just c)->c)$…

से लंबा है

m(Just c)=c;f x=m$…

से लंबा है

f x|Just c<-…=c

वास्तव में, वे डिकॉन्स्ट्रक्ट करने के बजाय सादे पुराने मूल्य को बांधने पर भी छोटे होते हैं: xnor की टिप देखें


खैर,
लंबोदर

1
मैं मान रहा हूं कि eवास्तव में एक टोकन नहीं है, लेकिन एक लंबी अभिव्यक्ति है $जो इसके पहले की आवश्यकता है, जो आमतौर पर मामला है।
लिन

11

छोटा सशर्त

last$x:[y|b]

के बराबर है

if b then y else x

यहां देखिए यह कैसे काम करता है:

             [y|b]   x:[y|b]   last$x:[y|b]
if...      +--------------------------------
b == False | []      [x]       x
b == True  | [y]     [x,y]     y

क्या यह होना चाहिए if b then y else x?
आकांक्षा

@ChristianIrwan अच्छा कैच, हां।
xnor

के boolरूप में आप एक सूची समझ की आवश्यकता नहीं है छोटा का उपयोग कर रहा हूँ
आलू

@ पोटैटो44 डेटा में है। बूल, जिसे आयात करने के लिए बाइट्स का खर्च आता है।
xnor

11

माइनस साइन के साथ काम करना

माइनस साइन -कई सिंटैक्स नियमों के लिए एक कष्टप्रद अपवाद है। यह टिप हास्केल में नकारात्मकता और घटाव को व्यक्त करने के कुछ छोटे तरीकों को सूचीबद्ध करता है। कृपया मुझे बताएं कि क्या मैंने कुछ याद किया है।

नकार

  • एक अभिव्यक्ति को नकारने के लिए e, बस करो -e। उदाहरण के लिए, -length[1,2]देता है-2
  • यदि eसमान रूप से जटिल है, तो आपको चारों ओर कोष्ठक की आवश्यकता होगी e, लेकिन आप आमतौर पर एक बाइट को उनके चारों ओर ले जाकर बचा सकते हैं: -length(take 3 x)से कम है -(length$take 3 x)
  • यदि eपहले से =या 6 से कम की शुद्धता के एक इन्फिक्स ऑपरेटर से पहले है , तो आपको एक स्थान की आवश्यकता है: यदि कम से कम है तो f= -2परिभाषित करता है fऔर k< -2परीक्षण करता kहै -2। यदि नियतता 6 या अधिक है, तो आपको पैरेन्स की आवश्यकता है: 2^^(-2)देता है 0.25। आप आमतौर पर इन से छुटकारा पाने के लिए सामान को पुनर्व्यवस्थित कर सकते हैं: उदाहरण के लिए, इसके -k>2बजाय k< -2
  • इसी तरह, यदि !एक ऑपरेटर है, तो -a!bयह (-a)!bमान लिया जाता है कि जैसे कि फिक्सिटी !अधिकतम 6 पर है (इसलिए -1<1देता है True), और -(a!b)अन्यथा (इसलिए -[1,2]!!0देता है -1)। उपयोगकर्ता-परिभाषित ऑपरेटरों और पिछले कार्यों की डिफ़ॉल्ट शुद्धता 9 है, इसलिए वे दूसरे नियम का पालन करते हैं।
  • किसी फ़ंक्शन में नकार को चालू करने के लिए ( mapआदि के साथ उपयोग करने के लिए ), अनुभाग का उपयोग करें (0-)

घटाव

  • एक फ़ंक्शन प्राप्त करने के लिए जो घटता है k, अनुभाग का उपयोग करें (-k+), जो जोड़ता है -kkयहां तक ​​कि एक बहुत ही जटिल अभिव्यक्ति हो सकती है: (-2*length x+)अपेक्षा के अनुरूप काम करती है।
  • 1 को घटाने के लिए, predइसके बजाय का उपयोग करें , जब तक कि इसे दोनों तरफ एक स्थान की आवश्यकता न हो। यह दुर्लभ है और आमतौर पर untilउपयोगकर्ता-परिभाषित फ़ंक्शन के साथ होता है , क्योंकि map pred xइसे pred<$>xऔर इसके iterate pred xद्वारा प्रतिस्थापित किया जा सकता है [x,x-1..]। और अगर आपके पास f pred xकहीं है, तो आपको शायद fवैसे भी एक infix फ़ंक्शन के रूप में परिभाषित करना चाहिए । इस टिप को देखें ।

11

फ़ंक्शन परिभाषाओं और / या तर्कों को पुन: व्यवस्थित करने का प्रयास करें

फ़ंक्शन परिभाषा में पैटर्न-मिलान मामलों के क्रम को बदलकर आप कभी-कभी कुछ बाइट्स बचा सकते हैं। ये बचत सस्ती हैं, लेकिन अनदेखी करने में आसान हैं।

एक उदाहरण के रूप में, इस उत्तर के पहले के संस्करण (एक भाग) पर विचार करें :

(g?x)[]=x
(g?x)(a:b)=g(g?x$b)a

यह एक पुनरावर्ती परिभाषा है ?, जिसका आधार मामला रिक्त सूची है। चूंकि []उपयोगी मूल्य नहीं है, हमें परिभाषाओं को स्वैप करना चाहिए और इसे वाइल्डकार्ड _या डमी तर्क के साथ बदलना चाहिए y, जिससे बायपास की बचत होगी:

(g?x)(a:b)=g(g?x$b)a
(g?x)y=x

उसी उत्तर से, इस परिभाषा पर विचार करें:

f#[]=[]
f#(a:b)=f a:f#b

खाली सूची रिटर्न वैल्यू में होती है, इसलिए हम मामलों को स्वैप करके दो बाइट्स बचा सकते हैं:

f#(a:b)=f a:f#b
f#x=x

साथ ही, फ़ंक्शन तर्कों का क्रम कभी-कभी आपको अनावश्यक व्हाट्सएप को हटाने की अनुमति देकर फर्क कर सकता है। इस उत्तर के पुराने संस्करण पर विचार करें :

h p q a|a>z=0:h p(q+2)(a-1%q)|1<2=1:h(p+2)q(a+1%p)

वहाँ के बीच खाली स्थान के की एक कष्टप्रद टुकड़ा है hऔर pपहली शाखा में। हम h a p qइसके बजाय परिभाषित करके इससे छुटकारा पा सकते हैं h p q a:

h a p q|a>z=0:h(a-1%q)p(q+2)|1<2=1:h(a+1%p)(p+2)q

10

"अन्यथा" गार्ड बर्बाद मत करो

एक अंतिम गार्ड जो कि एक चर को बांधने के लिए एक कैच-ऑल True(जितना छोटा 1>0) का उपयोग किया जा सकता है। की तुलना करें:

... |1>0=1/(x+y)
... |z<-x+y=1/z

... |1>0=sum l-sum m
... |s<-sum=s l-s m

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


10

गार्ड ,की जगह इस्तेमाल करें&&

एक गार्ड में कई शर्तें जो सभी को पकड़नी पड़ती हैं, के ,बजाय के साथ जोड़ा जा सकता है &&

f a b | a/=5 && b/=7 = ...
f a b | a/=5 ,  b/=7 = ...

2
इसकी शर्तें भी नहीं हैं, आप इस तरह की चीजें कर सकते हैं:f xs m | [x] <- xs, Just y <- m, x > 3 = y
ब्लैककैप

10

स्थानीय घोषणाओं के लिए छोटा सिंटैक्स

कभी-कभी आपको एक स्थानीय फ़ंक्शन या ऑपरेटर को परिभाषित करने की आवश्यकता होती है, लेकिन अतिरिक्त तर्क जोड़कर इसे लिखने whereया let…inइसे शीर्ष-स्तर तक उठाने के लिए बहुत सारे बाइट्स खर्च होते हैं ।

g~(a:b)=2!g b where k!l=k:take(a-1)l++(k+1)!drop(a-1)l
g~(a:b)=let k!l=k:take(a-1)l++(k+1)!drop(a-1)l in 2!g b
g~(a:b)=2!g b$a;(k!l)a=k:take(a-1)l++((k+1)!drop(a-1)l)a

सौभाग्य से, हास्केल के पास स्थानीय घोषणाओं के लिए एक भ्रामक और शायद ही कभी इस्तेमाल किया गया, लेकिन यथोचित वाक्यविन्यास है :

fun1 pattern1 | let fun2 pattern2 = expr2 = expr1

इस मामले में:

g~(a:b)|let k!l=k:take(a-1)l++(k+1)!drop(a-1)l=2!g b

आप इस वाक्यविन्यास का उपयोग मल्टी-स्टेटमेंट घोषणाओं या कई घोषणाओं के साथ कर सकते हैं, और यह घोंसला भी बनाती है:

fun1 pattern1 | let fun2 pattern2 = expr2; fun2 pattern2' = expr2' = expr1
fun1 pattern1 | let fun2 pattern2 = expr2; fun3 pattern3 = expr3 = expr1
fun1 pattern1 | let fun2 pattern2 | let fun3 pattern3 = expr3 = expr2 = expr1

यह बाध्यकारी चर या अन्य पैटर्न के लिए भी काम करता है, हालांकि पैटर्न गार्ड इसके लिए छोटे होते हैं जब तक कि आप बाध्यकारी कार्य भी नहीं करते हैं।


3
यह सूची बोध के अंदर भी काम करता है [f 1|let f x=x+1]:।
लकोनी

10

से बचें repeat n

-- 8 bytes, whitespace might be needed before and after
repeat n

-- 8 bytes, whitespace might be needed before
cycle[n]

-- 7 bytes, whitespace might be needed before and after, can be reused,
-- needs an assignment, n needs to be global
l=n:l;l

-- 7 bytes, never needs whitespace, n needs to derive from Enum,
-- n has to be short enough to be repeated twice
[n,n..]

या तो उन चार अभिव्यक्तियों में से एक अनंत सूची का उत्पादन करेगा n

यह एक बहुत ही विशिष्ट टिप है लेकिन यह 3 बाइट तक बचा सकता है !


4
यदि nवैश्विक है, l=n:l;lतो समान लंबाई है और (कुछ) लंबी अभिव्यक्तियों के लिए काम करता है। (हालांकि
व्हॉट्सएप

@ TherjanJohansen मैंने इसे पोस्ट में शामिल किया। धन्यवाद!
पूरी तरह से

10

जब एक परिणाम खाली सूची है, तो शोर्ट कंडिशनर्स

जब आपको एक सशर्त की आवश्यकता होती है जो कुछ शर्त के आधार पर सूची Aया खाली सूची लौटाता है , तो सामान्य सशर्त निर्माणों के कुछ छोटे विकल्प मौजूद होते हैं:[]C

if(C)then(A)else[] -- the normal conditional
last$[]:[A|C]      -- the golfy all-round-conditional
concat[A|C]        -- shorter and works when surrounded by infix operator
id=<<[A|C]         -- even shorter but might conflict with other infix operators
[x|C,x<-A]         -- same length and no-conflict-guarantee™
[0|C]>>A           -- shortest way, but needs surrounding parenthesis more often than not

उदाहरण: 1 , 2


दूसरा एक है Aऔर []बंद।
अर्जन जोहान्सन

@ ThanksrjanJohansen सही किया, धन्यवाद!
लकोनी

1
अहा! लेकिन *>उच्चतर स्थिरता है >>(अभी भी आराम के लिए थोड़ा कम है।)
अर्जन जोहान्सन

9

लैम्ब्डा पार्सिंग नियम

एक लैम्ब्डा-अभिव्यक्ति को वास्तव में इसके चारों ओर कोष्ठक की आवश्यकता नहीं है - यह सिर्फ लालच से सब कुछ पकड़ लेता है इसलिए पूरी चीज अभी भी पर्स, उदाहरण के लिए

  • एक समापन पैरा - (foo$ \x -> succ x)
  • एक में - let a = \x -> succ x in a 4
  • रेखा के अंत - main = getContents>>= \x -> head $ words x
  • आदि..

सामना किया गया है, और कुछ अजीब धार-मामले हैं जहां यह आपको एक बाइट या दो बचा सकता है। मेरा मानना ​​है कि \इसका उपयोग ऑपरेटरों को परिभाषित करने के लिए भी किया जा सकता है, इसलिए इसका दोहन करते समय आपको ऑपरेटर के बाद सीधे लैम्बडा लिखते समय एक स्थान की आवश्यकता होगी (जैसे तीसरे उदाहरण में)।

यहाँ एक उदाहरण है कि लैम्बडा का उपयोग करना सबसे छोटी चीज थी जिसका मैं पता लगा सकता था। कोड मूल रूप से दिखता है:

a%f=...
f t=sortBy(% \c->...)['A'..'Z']

9

लंबोदर letद्वारा प्रतिस्थापित

यह आमतौर पर एक अकेला सहायक परिभाषा को छोटा कर सकता है जो किसी कारण से किसी गार्ड के साथ बाध्य नहीं हो सकता है या वैश्विक रूप से परिभाषित नहीं हो सकता है। उदाहरण के लिए, प्रतिस्थापित करें

let c=foo a in bar

3 बाइट्स छोटे से

(\c->bar)$foo a

कई सहायक परिभाषाओं के लिए, परिभाषाओं की संख्या के आधार पर, लाभ संभवतः छोटा है।

let{c=foo a;n=bar a}in baz
(\c n->baz)(foo a)$bar a

let{c=foo a;n=bar a;m=baz a}in qux
(\c n m->qux)(foo a)(bar a)$baz a

let{c=foo a;n=bar a;m=baz a;l=qux a}in quux
(\c n m l->quux)(foo a)(bar a)(baz a)$qux a

यदि कुछ परिभाषाएँ दूसरों को संदर्भित करती हैं, तो बाइट्स को बचाना और भी कठिन है:

let{c=foo a;n=bar c}in baz
(\c->(\n->baz)$bar c)$foo a

इसके साथ मुख्य चेतावनी यह है कि letआप बहुरूपता चर को परिभाषित करने की अनुमति देते हैं, लेकिन lambdas @ChristianSievers द्वारा उल्लेख नहीं किया गया है। उदाहरण के लिए,

let f=length in(f["True"],f[True])

परिणाम (1,1), लेकिन

(\f->(f["True"],f[True]))length

एक प्रकार की त्रुटि देता है।


1
यह शायद ही कभी मायने रखता है, लेकिन "शब्दार्थ समतुल्य" थोड़ा बहुत वादा करता है। हमारे पास बहुरूपी है let, इसलिए हम कर सकते हैं let f=id in (f 0,f True)। अगर हम इसे लैम्ब्डा के साथ फिर से लिखने की कोशिश करते हैं तो यह चेक टाइप नहीं करता है।
क्रिश्चियन सिवर्स

@ChristianSievers यह सच है, नोट के लिए धन्यवाद। मैंने इसे संपादित किया।
जर्गब

8

गार्ड का उपयोग कर बाँध

एक नामित फ़ंक्शन को परिभाषित करते समय, आप एक गार्ड में एक चर के लिए एक अभिव्यक्ति को बांध सकते हैं। उदाहरण के लिए,

f s|w<-words s=...

के रूप में ही करता है

f s=let w=words s in ...
f s=(\w->...)$words s

दोहराया अभिव्यक्तियों पर सहेजने के लिए इसका उपयोग करें। जब अभिव्यक्ति का दो बार उपयोग किया जाता है, तो यह लंबाई 6 पर भी टूट जाती है, हालांकि रिक्ति और पूर्वता के मुद्दे इसे बदल सकते हैं।

(उदाहरण में, यदि मूल चर sका उपयोग नहीं किया गया है, तो ऐसा करना कम है

g w=...
f=g.words

लेकिन यह अधिक जटिल अभिव्यक्तियों को बांधने के लिए सही नहीं है।)


क्या इस उत्तर का डुप्लिकेट / विशेष मामला नहीं है ?
लिन

@Lynn पीछे देखते हुए, यह एक विशेष मामला है, लेकिन जब मैंने उस उत्तर को पढ़ा, तो Justउदाहरण ने मुझे यह समझा कि यह एक कंटेनर से निकालने के लिए पैटर्न-मिलान के लिए है, बजाय एक अभिव्यक्ति पर स्टोर करने के।
xnor

8

तुलना (0<$)के lengthलिए उपयोग करें

यदि परीक्षण एक सूची aकी तुलना में लंबा है b, तो आमतौर पर कोई लिख देगा

length a>length b

हालाँकि, दोनों सूचियों के प्रत्येक तत्व को समान मान के साथ प्रतिस्थापित 0किया जा सकता है , उदाहरण के लिए , और फिर उन दो सूचियों की तुलना कम हो सकती है:

(0<$a)>(0<$b)

इसे ऑनलाइन आज़माएं!

कोष्ठक क्योंकि जरूरत है <$और तुलना ऑपरेटरों ( ==, >, <=, ...), हालांकि कुछ अन्य मामलों में वे की जरूरत नहीं किया जा सकता है, एक ही पूर्वता स्तर 4 है और भी बाइट्स बचत।


8

छोटा transpose

transposeसमारोह Data.Listका उपयोग करने के लिए आयात किया जाना है। यदि आयात के लिए यह एकमात्र कार्य है, तो निम्नलिखित की foldrपरिभाषा का उपयोग करके एक बाइट बचा सकता है transpose:

import Data.List;transpose
e=[]:e;foldr(zipWith(:))e

ध्यान दें कि व्यवहार केवल समान लंबाई वाली सूचियों की सूची के लिए समान है।

मैंने यहाँ इसका सफल प्रयोग किया ।


8

प्रत्यय प्राप्त करें

scanr(:)[]किसी सूची के प्रत्यय प्राप्त करने के लिए उपयोग करें :

λ scanr(:)[] "abc"
["abc","bc","c",""]

यह tailsबाद की तुलना में बहुत कम है import Data.List। आप उपसर्ग कर सकते हैं scanr(\_->init)=<<id(अर्जन जोहानसन द्वारा पाया गया)।

λ  scanr(\_->init)=<<id $ "abc"
["","a","ab","abc"]

यह एक बाइट को बचाता है

scanl(\s c->s++[c])[]

शायद scanl(flip(:))[] "abc"= ["","a","ba","cba"]यह भी ध्यान देने योग्य है - कभी-कभी उपसर्ग पीछे की ओर होने से कोई फर्क नहीं पड़ता।
लिन

3
अर्जन जोहानसन को उपसर्गों के लिए एक-एक बाइट छोटा विकल्प मिला:scanr(\_->init)=<<id
लाईकोनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.