คำตอบ:
import StdEnv
เมื่อเป็นไปได้ในการเข้าถึงฟังก์ชั่นแม้กระทั่งขั้นพื้นฐานดูเหมือนจะชอบ(==)
หรือmap
คำสั่งนำเข้าเป็นสิ่งจำเป็นมักจะimport StdEnv
เพราะมันนำเข้าโมดูลที่พบมากที่สุดเช่นStdInt
, StdBool
และอื่น ๆ (ดูที่นี่สำหรับข้อมูลเพิ่มเติมเกี่ยวStdEnv
)
อย่างไรก็ตามอาจเป็นไปได้ที่จะหลีกเลี่ยงการนำเข้านี้สำหรับความท้าทายบางอย่างและใช้คุณลักษณะภาษาหลักเช่นความเข้าใจในรายการและการจับคู่รูปแบบ
ตัวอย่างเช่นแทนที่จะเป็น
import StdEnv
map f list
หนึ่งสามารถเขียน
[f x\\x<-list]
ฟังก์ชันหรือการเรียกใช้ฟังก์ชันบางอย่างที่ต้องการimport StdEnv
ทางเลือกที่ไม่ต้องการการนำเข้าและการประมาณคร่าวๆของไบต์ที่บันทึกไว้
hd
-> (\[h:_]=h)
, ~ 6 ไบต์tl
-> (\[_:t]=t)
, ~ 6 ไบต์map f list
-> [f x\\x<-list]
, ~ 10 ไบต์filter p list
-> [x\\x<-list|p x]
, ~ 11 ไบต์(&&)
-> %a b|a=b=a;%
, ~ 6 ไบต์(||)
-> %a b|a=a=b;%
, ~ 6 ไบต์not
-> %a|a=False=True;%
, ~ 1 ไบต์and
-> %[a:r]|a= %r=a;%_=True
, ~ 0 ไบต์or
-> %[a:r]|a=a= %r;%_=False
, ~ 0 ไบต์ไม่กี่คนสุดท้ายที่ไม่น่าจะบันทึกไบต์ได้จริงเนื่องจากการแทนที่โดยตรงให้ผลตอบแทนมากกว่าไบต์ที่นำเข้า แต่อาจเป็นไปได้ในกรณีที่จำเป็นต้องมีการเรียกซ้ำในรายการ
map f list -> [f x\\x<-list] (11 bytes saved)
(หรือบางอย่างที่คล้ายกัน))
ท้ายที่สุดแล้วทุกคนสามารถเล่นกอล์ฟในภาษาที่พวกเขาไม่สามารถใช้!
ออนไลน์
ทำความสะอาดไม่ใช่ภาษาที่รู้จักกันดีหรือมีเอกสารดีและชื่อไม่ได้ทำให้ง่ายต่อการค้นหาแหล่งข้อมูลที่จำเป็นมากในการแก้ไขปัญหาเหล่านี้ ... หรือไม่
Clean เดิมเรียกว่าConcurrent Cleanซึ่งยังคงใช้ในส่วนนำหน้าของเอกสารเกือบทั้งหมดที่เกี่ยวข้องกับ Clean - ดังนั้นหากคุณกำลังมองหา Clean ให้มองหา Clean พร้อมกันแทน
หนึ่งในความคล้ายคลึงที่น่าทึ่งยิ่งกว่าของ Clean คือ Haskell (ซึ่งมีอยู่มากมาย) คือการมีอยู่ของCloogleซึ่งเป็นเครื่องมือค้นหาฟังก์ชั่นที่ครอบคลุมไลบรารีที่ Clean มาพร้อมกับ
ในท้องถิ่น
ไลบรารีที่ Clean จัดส่งด้วยนั้นอยู่ในรูปแบบของไฟล์ซอร์ส Clean ที่มีการติติงด้วยความคิดเห็นที่ค่อนข้างเหมาะสมซึ่งสามารถเรียกดูผ่านการใช้ IDE
(นอกจากนี้ยังมาพร้อมกับโปรแกรมตัวอย่างแบบเต็มภายใต้$INSTALL/Examples
)
เมื่อพูดถึง Clean เวอร์ชัน Windows มาพร้อมกับ IDE - แม้ว่ามันจะถูก จำกัด ด้วยมาตรฐานที่ทันสมัย แต่โลกก็ยังดีกว่าการใช้เท็กซ์เอดิเตอร์และบรรทัดคำสั่ง
คุณสมบัติที่มีประโยชน์มากที่สุดสองประการ (ในบริบทของการเรียนรู้) คือ:
[Ctrl]+[D]
เพื่อเปิดไฟล์คำจำกัดความ (หรือใช้[Ctrl]+[I]
สำหรับไฟล์การนำไปใช้) และสลับระหว่างคำจำกัดความและไฟล์การนำไปปฏิบัติด้วย[Ctrl]+[/]
คอมไพเลอร์ของ Clean ไม่สนใจว่าการเข้ารหัสใดที่คุณคิดว่าคุณได้บันทึกไฟล์ต้นฉบับไว้เช่นเดียวกับค่าไบต์ในไฟล์ สิ่งนี้มีผลตามมาอย่างเรียบร้อย
ในร่างกายของรหัสที่มาเพียงไบต์ด้วยรหัสจุดที่สอดคล้องกับตัวอักขระ ASCII \t\r\n
ได้รับอนุญาตนอกจากนั้นสำหรับ
ตัวอักษร:
ในString
และ[Char]
ตัวอักษร ( "stuff"
และ['stuff']
ตามลำดับ) ไบต์ใด ๆ ยกเว้น 0ได้รับอนุญาตด้วยข้อแม้ที่"
และ'
จะต้องหลบหนี (สำหรับString
และ[Char]
ตามลำดับ) และการขึ้นบรรทัดใหม่และผลตอบแทน carraige จะต้องถูกแทนที่ด้วย\n
และ\r
(ยังตามลำดับ)
ในChar
ตัวอักษรไบต์ใด ๆ ยกเว้น 0ได้รับอนุญาตหมายความว่า:
'\n'
'
'
เหมือนกัน แต่ที่สองคือหนึ่งไบต์ที่สั้นกว่า
หนี:
นอกเหนือจากการ\t\r\n
หลีกเลี่ยงจดหมายมาตรฐาน(ฯลฯ ) ลำดับการหลีกเลี่ยงที่ไม่ใช่ตัวเลขทั้งหมดใน Clean จะใช้สำหรับเครื่องหมายทับหรือสำหรับเครื่องหมายคำพูดที่ใช้เพื่อกำหนดขอบเขตตัวอักษรที่อยู่ภายใน
สำหรับลำดับ escape ตัวเลขตัวเลขจะถือว่าเป็นค่าฐานแปดที่ถูกยกเลิกหลังจากสามหลัก ซึ่งหมายความว่าหากคุณต้องการโมฆะตามด้วยตัวอักษร1
ในString
คุณจำเป็นต้องใช้"\0001"
(หรือ"\0\61"
) และไม่ได้ "\01"
อย่างไรก็ตามถ้าคุณทำตามการหลบหนีด้วยอะไรก็ได้ยกเว้นตัวเลขคุณสามารถละเว้นเลขศูนย์นำหน้าได้
ผลกระทบ:
การเล่นโวหารด้วยวิธีที่ Clean จัดการกับไฟล์ต้นฉบับช่วยให้String
และ['Char']
กลายเป็นลำดับของตัวเลขหลักเดียว 256 หลักได้อย่างมีประสิทธิภาพซึ่งมีการใช้งานมากมายสำหรับ code-golf เช่นการจัดเก็บดัชนี (สูงสุด 255 รายการ)
เมื่อกำหนดฟังก์ชั่นมักจะสั้นกว่าที่จะใช้การรวมกันบางส่วนของ!@$%^&*~-+=<:|>.?/\
กว่าจะใช้ตัวอักษรและตัวเลขเพราะมันช่วยให้คุณสามารถเว้นช่องว่างระหว่างตัวระบุ
ตัวอย่างเช่น: ?a=a^2
สั้นกว่าf a=a^2
และการเรียกใช้จะสั้นกว่าเช่นกัน
อย่างไรก็ตาม :
หากมีการใช้ฟังก์ชั่นตัวระบุติดกับสัญลักษณ์อื่น ๆซึ่งสามารถรวมกันเป็นรูปแบบที่แตกต่างกัน แต่ตัวระบุที่ถูกต้องพวกเขาทั้งหมดจะถูกแยกวิเคราะห์เป็นหนึ่งตัวบ่งชี้และคุณจะเห็นข้อผิดพลาด
ตัวอย่างเช่น: ?a+?b
แยกวิเคราะห์เป็น? a +? b
นอกจากนี้:
มันเป็นไปได้ที่จะเขียนทับตัวบ่งชี้ที่นำเข้าในที่สะอาดและอื่น ๆ เพียงตัวเดียวตัวระบุสัญลักษณ์ที่ไม่ได้ใช้แล้วในการเป็นStdEnv
@$?
การเขียนทับ^-+
(ฯลฯ ) อาจมีประโยชน์หากคุณต้องการตัวระบุสัญลักษณ์เพิ่มเติม แต่ระวังว่าคุณไม่ได้เขียนทับสิ่งที่คุณกำลังใช้อยู่
บางส่วนของโครงสร้างที่แข็งแกร่ง (สำหรับการเล่นกอล์ฟ) let ... in ...
ในภาษาที่ทำงานได้ดี
สะอาดของหลักสูตรมีนี้และสิ่งที่ดีกว่า - #
The
โหนดคืออะไร
ทั้งสะอาด#
และแพร่หลาย|
(ยามรูปแบบ) เป็นที่รู้จักกันทั้งสองเป็น 'การแสดงออกโหนด'
โดยเฉพาะอย่างยิ่งพวกเขาช่วยให้คุณสามารถตั้งโปรแกรม imperatively- ishในที่สะอาด (Clean ซึ่งเป็นสิ่งที่ดีจริงๆที่นี่!)
#
(ขอก่อน):
ทั้งสองนี้คำนวณค่าของจำนวนเต็มที่กำหนดเป็นสตริงคูณด้วยผลรวมของตัวอักษร
f s=let i=toInt s;n=sum[toInt c\\c<-:s]in n*i
f s#i=toInt s
#s=sum[toInt c\\c<-:s]
=s*i
โปรดทราบว่ารุ่นที่มี#
จะสั้นลงอย่างไรและเราจะกำหนดใหม่s
ได้อย่างไร สิ่งนี้มีประโยชน์หากเราไม่ต้องการค่าที่ตัวแปรมีเมื่อเราได้รับดังนั้นเราจึงสามารถใช้ชื่อได้อีกครั้ง ( let
สามารถพบปัญหาเมื่อคุณทำเช่นนั้น)
แต่การใช้let
จะง่ายกว่าเมื่อคุณต้องการบางสิ่งflip f = let g x y = f y x in g
The |
(รูปแบบการป้องกัน):
รูปแบบการป้องกันของ Clean สามารถใช้งานได้เหมือนกับภาษาอื่น ๆ ที่มีฟังก์ชั่นการใช้งานif ... else ...
มากมาย และเวอร์ชันที่สั้นกว่าของนิพจน์ประกอบไปด้วย
ตัวอย่างเช่นสิ่งเหล่านี้ทั้งหมดส่งคืนสัญลักษณ์ของจำนวนเต็ม:
s n|n<>0|n>0=1= -1
=0
s n=if(n<>0)if(n>0)1(-1)0
s n|n>0=1|n<0= -1=0
แน่นอนคนสุดท้ายที่ใช้ยามมากกว่าเดิมคือสั้นที่สุด แต่คนแรกแสดงให้เห็นว่าคุณสามารถซ้อนมันได้ (แต่เพียงสองประโยคที่ไม่มีเงื่อนไขกลับสามารถปรากฏในบรรทัดเดียวกันในรูปแบบกฎ) และที่สองแสดงสิ่งที่ คนแรกไม่มีเหตุผล
หมายเหตุ:
คุณสามารถใช้นิพจน์เหล่านี้ได้ทุกที่ ใน lambdas, case ... of
, let ... in
ฯลฯ
String
คุณควรใช้งานText
การแปลงเป็นสายอักขระและการจัดการกับสายอักขระ (ตัว{#Char}
/ String
ไม่ใช่[Char]
แบบชนิด) ค่อนข้างยาวและไม่ดีสำหรับการเล่นกอล์ฟ Text
เยียวยาโมดูลนี้
การแปลง:
Text
กำหนดผู้ประกอบการ<+
สำหรับสองประเภทใด ๆ ที่ได้toString
กำหนดไว้
ผู้ประกอบการนี้ใช้เป็นa<+b
เป็นเช่นเดียวกับtoString a+++toString b
- ประหยัดอย่างน้อย 19 ไบต์ แม้ว่าคุณจะรวมการนำเข้าเพิ่มเติม,Text
และใช้เพียงครั้งเดียวก็ยังบันทึกได้ 14 ไบต์!
การจัดการ:
Text
กำหนดลวดเย็บกระดาษการจัดการสตริงที่หายไปจากStdEnv
:
+
สำหรับสตริงซึ่งสั้นกว่า+++
(จากStdEnv
)indexOf
โดยมีพฤติกรรมคล้าย C ในการส่งคืน-1
แทนที่จะเป็นNothing
ความล้มเหลวconcat
ซึ่งจะเชื่อมโยงรายการสตริงjoin
ซึ่งรวมรายการของสตริงโดยใช้สตริงตัวคั่นsplit
ซึ่งแยกสตริงเป็นรายการสตริงบนสตริงย่อยบางครั้งคุณพบว่าตัวเองใช้แลมบ์ดาแสดงออก (เพื่อส่งต่อmap
หรือsortBy
ฯลฯ ) เมื่อคุณทำเช่นนี้ (เขียน lambdas) มีหลายวิธีที่คุณสามารถทำได้
ทางที่ถูก:
นี่คือsortBy
รายการเรียงลำดับแลมบ์ดาที่มีสำนวนยาวที่สุดถึงสั้นที่สุด
sortBy (\a b = length a > length b)
อีกวิธีที่ถูกต้อง:
หากคุณกำลังใช้Data.Func
งานคุณสามารถทำได้
sortBy (on (>) length)
ทางสั้น ๆ :
นี่คือสิ่งเดียวกัน แต่มีไวยากรณ์นักกอล์ฟ
sortBy(\a b=length a>length b)
วิธีอื่น ๆ :
การใช้การแต่งเพลงไม่ได้สั้นลงในครั้งนี้ แต่บางครั้งอาจสั้นกว่านี้ได้
sortBy(\a=(>)(length a)o length)
วิธีอื่น ๆ :
ในขณะที่มันถูกประดิษฐ์ขึ้นเล็กน้อยที่นี่คุณสามารถใช้การ์ดใน lambdas
sortBy(\a b|length a>length b=True=False)
และยังให้นิพจน์โหนดก่อน
sortBy(\a b#l=length
=l a>l b)
หมายเหตุ:
มีอีกสองรูปแบบของแลมบ์ดามี(\a b . ...)
และ(\a b -> ...)
หลังซึ่งเป็นเหมือน=
ที่แตกต่างและอดีตซึ่งมีอยู่ด้วยเหตุผลบางอย่างและมักจะดูเหมือนว่าคุณกำลังพยายามที่จะเข้าถึงทรัพย์สินของบางสิ่งบางอย่างแทนการกำหนดแลมบ์ดาเพื่อ don ใช้งานไม่ได้
\a=...
คือไวยากรณ์แลมบ์ดาของ Clean: P
on(<)length
แม้ว่าData.Func
การนำเข้าจะทำให้คุณเลิกเว้นแต่ว่าคุณต้องการมันอยู่แล้ว
#
) เป็น lambdas ได้ด้วย
ตัวอักษรรายชื่อตัวละครเป็นวิธีที่จดชวเลขการเขียนสิ่งที่ต้องการเป็น['h','e','l','l','o']
['hello']
นี่ไม่ใช่ขีด จำกัด ของสัญกรณ์ตัวอย่างเช่น:
repeat'c'
กลาย['c','c'..]
เป็น['cc'..]
['z','y'..'a']
กลายเป็น ['zy'..'a']
['beginning']++[a,b,c]++['end']
กลายเป็น ['beginning',a,b,c,'end']
['prefix']++suffix
กลายเป็น ['prefix':suffix]
งานเหล่านี้ในการจับคู่เกินไป:
['I don't care about the next character',_,'but I do care about these ones!']
code
ก็สั้นClean มีฟังก์ชั่นที่มีประโยชน์มากมายในไลบรารีมาตรฐานซึ่งบางฟังก์ชั่นใช้งานได้อย่างไม่น่าเชื่อ *World
และการใช้*World
code-golf เป็นความคิดที่ไม่ดีอยู่แล้ว
เพื่อแก้ไขปัญหานี้บ่อยครั้ง ccall
คุณสามารถใช้code
บล็อกภายในแทน
ตัวอย่างบางส่วน:
เวลาของระบบ
import System.Time,System._Unsafe
t=toInt(accUnsafe(time))
ด้านบนคือ 58 ไบต์ แต่คุณสามารถบันทึก 17 ไบต์ (ลงไปที่ 40 + 1) ด้วย:
t::!Int->Int
t _=code{ccall time "I:I"
}
ตัวเลขสุ่ม
อันนี้ไม่ได้บันทึกไบต์ด้วยตัวเอง แต่หลีกเลี่ยงการต้องผ่านรายการ genRandInt
s::!Int->Int
s _=code{ccall time "I:I"ccall srand "I:I"
}
r::!Int->Int
r _=code{ccall rand "I:I"
}
ใช้อื่น ๆ
นอกเหนือจากสองสิ่งนี้ซึ่งอาจใช้เป็นหลักในการเขียนโค้ดกอล์ฟคุณสามารถเรียกใช้ฟังก์ชันที่มีชื่อใด ๆ (รวมถึง แต่ไม่ จำกัด เฉพาะ syscall ทุกแห่ง) ฝังแอสเซมบลีตามอำเภอใจด้วยinstruction <byte>
และฝังโค้ดสำหรับเครื่อง ABC
import StdEnv
+a and b
(21 ไบต์) เล็กกว่า%[a:r]|a= %r=a;%_=True
(22 ไบต์) ใช่ไหม หรือจะเป็นimport StdEnv
+a=True and b=True
(31 ไบต์) ซึ่งในกรณีนี้มันสั้นกว่านี้อย่างแน่นอน (ผมไม่เคยโปรแกรมในสะอาดครับ.)