Mẹo chơi golf trong sạch


17

Bạn có lời khuyên chung nào cho việc chơi golf trong Clean? Vui lòng chỉ đăng các ý tưởng có thể được áp dụng cho các vấn đề về mã golf nói chung và ít nhất là phần nào cụ thể cho Clean.

Nếu bạn chưa bao giờ nghe về Clean, bạn có thể tìm hiểu thêm ở đây .
Hoặc, bạn có thể tham gia phòng trò chuyện .

Câu trả lời:


10

Tránh import StdEnvkhi có thể

Để truy cập các hàm dựng sẵn, ngay cả những hàm có vẻ cơ bản như (==)hoặc map, cần có một câu lệnh nhập, import StdEnvbởi vì nó nhập các mô-đun phổ biến nhất StdInt, StdBoolv.v. (xem tại đây để biết thêm thông tin StdEnv).

Tuy nhiên, có thể tránh việc nhập này cho một số thách thức và chỉ sử dụng các tính năng ngôn ngữ cốt lõi như hiểu danh sách và khớp mẫu.

Ví dụ, thay vì

import StdEnv 
map f list

người ta có thể viết

[f x\\x<-list]

Danh sách thay thế:

Một số chức năng hoặc các yêu cầu chức năng cần import StdEnv, một sự thay thế không cần nhập và ước tính sơ bộ các byte được lưu.

  • hd-> (\[h:_]=h), ~ 6 byte
  • tl-> (\[_:t]=t), ~ 6 byte
  • map f list-> [f x\\x<-list], ~ 10 byte
  • filter p list-> [x\\x<-list|p x], ~ 11 byte
  • (&&)-> %a b|a=b=a;%, ~ 6 byte
  • (||)-> %a b|a=a=b;%, ~ 6 byte
  • not-> %a|a=False=True;%, ~ 1 byte
  • and-> %[a:r]|a= %r=a;%_=True, ~ 0 byte
  • or-> %[a:r]|a=a= %r;%_=False, ~ 0 byte

Một số cuối cùng không có khả năng thực sự lưu byte, bởi vì một sự thay thế trực tiếp mang lại nhiều byte hơn so với việc nhập, nhưng có thể có thể xảy ra trong trường hợp cần đệ quy trên danh sách.

Mẹo này đã được sử dụng thành công ở đây .


Tuy nhiên, không phải là import StdEnv+ a and b(21 byte) nhỏ hơn %[a:r]|a= %r=a;%_=True(22 byte)? Hoặc nó sẽ là import StdEnv+ a=True and b=True(31 byte), trong trường hợp đó nó thực sự ngắn hơn? (Tôi chưa bao giờ lập trình trong Clean, btw.)
Kevin Cruijssen

@KevinCruijssen Chúng tôi chỉ thảo luận về điều đó trong trò chuyện . Đúng là chúng không có khả năng lưu byte, ngoại trừ có thể khi chương trình cần lặp lại danh sách.
Laikoni

4
À được rồi Có lẽ nó cũng có thể hữu ích để nói có bao nhiêu byte được lưu với thay thế (nghĩa là map f list -> [f x\\x<-list] (11 bytes saved)(hoặc một cái gì đó tương tự)).
Kevin Cruijssen

@KevinCruijssen Xong.
Laikoni

5

Biết học ngôn ngữ

Rốt cuộc, làm thế nào bất cứ ai có thể chơi golf bằng ngôn ngữ mà họ không thể sử dụng!

Trực tuyến

Clean không phải là một ngôn ngữ nổi tiếng hoặc được ghi chép tốt, và cái tên chắc chắn không giúp bạn dễ dàng tìm thấy các tài nguyên rất cần thiết để khắc phục những vấn đề này ... hay phải không?

Clean ban đầu được gọi là Clean Clean , vẫn được sử dụng trong lời nói đầu của hầu hết mọi tài liệu liên quan đến Clean - vì vậy nếu bạn đang tìm kiếm Clean, thay vào đó hãy tìm Clean Clean.

Một trong những điểm tương đồng đáng chú ý hơn của Clean với Haskell (trong đó có rất nhiều) là sự tồn tại của Cloogle , một công cụ tìm kiếm chức năng bao gồm các thư viện mà Clean ship có.

Tại địa phương

Các thư viện mà Clean ship có ở dạng bình luận, phần nào tự ghi lại các tệp nguồn sạch, có thể được duyệt qua bằng cách sử dụng IDE.
(Nó cũng đi kèm với các chương trình ví dụ đầy đủ, bên dưới $INSTALL/Examples.)

Nói về điều này, phiên bản Windows của Clean đi kèm với một IDE - trong khi nó bị giới hạn bởi các tiêu chuẩn hiện đại, nó tốt hơn so với việc sử dụng trình soạn thảo văn bản và dòng lệnh.
Hai tính năng hữu ích nhất (trong bối cảnh học tập) là:

  • Bạn có thể bấm đúp vào một lỗi để xem nó thuộc dòng nào
  • Bạn có thể đánh dấu tên mô-đun và nhấn [Ctrl]+[D]để mở tệp định nghĩa (hoặc sử dụng [Ctrl]+[I]cho tệp triển khai) và chuyển đổi giữa định nghĩa và tệp triển khai với[Ctrl]+[/]

4

Quên về mã hóa ký tự

Trình biên dịch của Clean không quan tâm đến mã hóa mà bạn nghĩ bạn đã lưu tệp nguồn, chỉ là về các giá trị byte trong tệp. Điều này có một số hậu quả gọn gàng.

Trong phần thân của mã nguồn, chỉ các byte có điểm mã tương ứng với các ký tự ASCII có thể in được cho phép, ngoài các ký tự cho \t\r\n.

Chữ:

Trong Stringvà bằng [Char]chữ ( "stuff"['stuff']tương ứng), bất kỳ byte nào ngoại trừ 0 đều được cho phép, với cảnh báo đó "'phải được thoát (cho String[Char]tương ứng), và các dòng mới và trả về carraige phải được thay thế bằng \n\r(cũng tương ứng).

Theo nghĩa Charđen, bất kỳ byte nào ngoại trừ 0 đều được phép, nghĩa là:

'\n'

'
'

Giống nhau, nhưng cái thứ hai ngắn hơn một byte.

Thoát:

Khác với các ký tự thoát tiêu chuẩn \t\r\n(v.v.), tất cả các chuỗi thoát không phải là số trong Clean đều dành cho dấu gạch chéo hoặc cho trích dẫn được sử dụng để phân định nghĩa đen của lối thoát bên trong.

Đối với các chuỗi thoát số, số được coi là giá trị bát phân kết thúc sau ba chữ số. Điều này có nghĩa là nếu bạn muốn null theo sau bởi ký tự 1trong a String, bạn cần sử dụng "\0001"(hoặc "\0\61") và không "\01" . Tuy nhiên, nếu bạn theo lối thoát với bất cứ thứ gì ngoại trừ số, bạn có thể bỏ qua các số 0 đứng đầu.

Kết quả:

Việc giải quyết vấn đề này với cách Clean xử lý các tệp nguồn của nó cho phép String['Char']thực sự trở thành chuỗi các số có một chữ số cơ bản 256 - có vô số cách sử dụng cho golf-code, chẳng hạn như lưu trữ các chỉ mục (tất nhiên lên tới 255).


3

Tên hàm với các ký hiệu

Khi xác định hàm, thường sử dụng một số kết hợp ngắn !@$%^&*~-+=<:|>.?/\hơn so với sử dụng các ký tự chữ và số, vì nó cho phép bạn bỏ qua khoảng trắng giữa các mã định danh.

Ví dụ: ?a=a^2ngắn hơn f a=a^2và gọi nó cũng ngắn hơn.

Tuy nhiên :

Nếu mã định danh hàm được sử dụng liền kề với các ký hiệu khác , có thể kết hợp để tạo thành một mã định danh khác, nhưng hợp lệ , tất cả chúng sẽ được phân tích cú pháp dưới dạng một mã định danh và bạn sẽ thấy lỗi.

Ví dụ: ?a+?bphân tích cú pháp như? a +? b

Ngoài ra:

Có thể ghi đè các số nhận dạng đã nhập trong Clean và do đó, số nhận dạng ký tự một ký tự duy nhất chưa được sử dụng StdEnv@$?. Ghi đè ^-+(vv) có thể hữu ích nếu bạn cần thêm số nhận dạng tượng trưng, ​​nhưng hãy cảnh giác rằng bạn không ghi đè lên bạn đang sử dụng.


3

Biết các nút K của bạn

Một số cấu trúc mạnh nhất (để chơi gôn) trong các ngôn ngữ chức năng là let ... in ....
Sạch tất nhiên, có cái này, và cái gì đó tốt hơn - cái #.

Một nút là gì?

Clean's #và ubiquitous |(mẫu bảo vệ) đều được gọi là 'biểu thức nút'.
Đáng chú ý, họ cho phép bạn để chương trình imperatively- ish trong sạch (mà thực sự tốt ở đây!).

Các #(let-trước đó):

Cả hai đều tính giá trị của một số nguyên được đưa ra dưới dạng một chuỗi, nhân với tổng số ký tự của nó

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

Lưu ý cách phiên bản #ngắn hơn và cách chúng tôi có thể xác định lại s. Điều này hữu ích nếu chúng ta không cần giá trị mà một biến có khi chúng ta nhận được nó, vì vậy chúng ta có thể sử dụng lại tên đó. ( letcó thể gặp vấn đề khi bạn làm điều đó)

Nhưng sử dụng letdễ dàng hơn khi bạn cần một cái gì đó nhưflip f = let g x y = f y x in g

Các |(mô hình bảo vệ):

Bảo vệ mẫu của Clean có thể được sử dụng như các ngôn ngữ chức năng khác - tuy nhiên nó cũng có thể được sử dụng như một mệnh lệnh if ... else .... Và một phiên bản ngắn hơn của biểu thức chim nhạn.

Ví dụ: tất cả đều trả về dấu của một số nguyên:

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

Tất nhiên, cái cuối cùng sử dụng bộ bảo vệ theo truyền thống là ngắn nhất, nhưng cái đầu tiên cho thấy bạn có thể lồng chúng (nhưng chỉ có hai mệnh đề trả về vô điều kiện có thể xuất hiện trên cùng một dòng trong quy tắc bố cục) và thứ hai cho thấy những gì đầu tiên làm một cách hợp lý.

Một lưu ý:

Bạn có thể sử dụng các biểu thức này về cơ bản bất cứ nơi nào. Trong lambdas, case ... of, let ... invv


1

Nếu bạn đang sử dụng, Stringbạn nên sử dụngText

Chuyển đổi thành chuỗi và thao tác dây ( loại {#Char}/ Stringkhông phải [Char]loại) khá dài và xấu cho việc chơi golf. Các Textmô-đun khắc phục điều này.

Chuyển đổi:

Textđịnh nghĩa toán tử <+cho bất kỳ hai loại đã toStringxác định.
Toán tử này, được sử dụng a<+bgiống như toString a+++toString b- tiết kiệm ít nhất 19 byte . Ngay cả khi bạn bao gồm nhập thêm ,Textvà chỉ sử dụng một lần, nó vẫn tiết kiệm được 14 byte!

Thao tác:

Textđịnh nghĩa một vài ghim thao tác chuỗi bị thiếu từ StdEnv:

  • Toán tử +cho chuỗi, ngắn hơn nhiều so với +++(từ StdEnv)
  • indexOf, với hành vi giống như C trở về -1thay vì Nothingthất bại
  • concat, nối một danh sách các chuỗi
  • join, tham gia danh sách các chuỗi bằng chuỗi phân cách
  • split, phân tách một chuỗi thành một danh sách các chuỗi trên một chuỗi con

1

Sử dụng lambdas ngắn hơn

Đôi khi bạn thấy mình sử dụng biểu thức lambda (để chuyển đến map, hoặc sortBy, v.v.). Khi bạn đang làm điều này (viết lambdas), có rất nhiều cách bạn có thể làm.

Đúng cách

Đây là sortBy, với một danh sách sắp xếp lambda thành ngữ từ dài nhất đến ngắn nhất

sortBy (\a b = length a > length b)

Cách khác đúng:

Nếu bạn đang sử dụng Data.Func, bạn cũng có thể làm

sortBy (on (>) length)

Con đường ngắn:

Đây là điều tương tự, nhưng với một cú pháp golfier

sortBy(\a b=length a>length b)

Cách khác:

Sử dụng thành phần không ngắn hơn lần này, nhưng đôi khi có thể ngắn hơn

sortBy(\a=(>)(length a)o length)

Một cách khác:

Mặc dù có một chút gì đó ở đây, bạn có thể sử dụng lính canh trong lambdas

sortBy(\a b|length a>length b=True=False)

Và cả biểu thức nút let-before

sortBy(\a b#l=length
=l a>l b)

Một lưu ý:

Có hai dạng lambda nữa, (\a b . ...)(\a b -> ...)dạng sau giống hệt với =biến thể, và dạng trước tồn tại vì một lý do nào đó và thường trông giống như bạn đang cố truy cập vào một tài sản của một thứ gì đó thay vì định nghĩa lambda nên không Không sử dụng nó.


1
Sau khi xem một số chương trình chơi gôn của bạn, tôi đã có ấn tượng \a=... cú pháp lambda thông thường của Clean: P
Ørjan Johansen

Bạn cũng có thể thêm các vệ sĩ trong lambda, như được sử dụng ở đây . Điều này là không có giấy tờ (thậm chí còn mâu thuẫn với báo cáo ngôn ngữ), nhưng hoạt động. Ngoài ra, ->=đối với lambdas là giống hệt như liên quan đến trình biên dịch (-> là cú pháp cũ). Chỉ .khác nhau (nhưng tôi không biết chính xác như thế nào).

Và trong ví dụ cụ thể này, bạn có thể cân nhắc sử dụng on(<)length , mặc dù việc Data.Funcnhập sẽ phá vỡ bạn trừ khi bạn cần nó.

@Keelan Mát mẻ. Tôi sẽ cập nhật điều này sau hôm nay. Tôi nghĩ bạn cũng có thể sử dụng let-before (# ) trong lambdas.
Οurous

Có, bạn có thể :-)

0

Sử dụng danh sách nhân vật

Một danh sách ký tự chữ là một cách viết tắt viết một cái gì đó giống như ['h','e','l','l','o']như ['hello'].

Đây không phải là giới hạn của ký hiệu, ví dụ:

  • repeat'c'trở ['c','c'..]thành['cc'..]
  • ['z','y'..'a'] trở thành ['zy'..'a']
  • ['beginning']++[a,b,c]++['end'] trở thành ['beginning',a,b,c,'end']
  • ['prefix']++suffix trở thành ['prefix':suffix]

Những công việc này phù hợp quá:

  • ['I don't care about the next character',_,'but I do care about these ones!']

0

Đôi khi codengắn hơn

Clean có một loạt các chức năng thực sự hữu ích trong các thư viện tiêu chuẩn, một số trong số đó rất dài để sử dụng mà không cần truy cập vào *World và sử dụng *Worldtrong code-golf nói chung là một ý tưởng tồi.

Để giải quyết vấn đề này, thường có ccall s bạn có thể sử dụng codecác khối bên trong .

Vài ví dụ:

Giờ hệ thống

import System.Time,System._Unsafe
t=toInt(accUnsafe(time))

Ở trên là 58 byte, nhưng bạn có thể lưu 17 byte (giảm xuống 40 + 1) với:

t::!Int->Int
t _=code{ccall time "I:I"
}

Số ngẫu nhiên

Cái này không tự lưu byte, nhưng tránh phải vượt qua một danh sách từ genRandInt

s::!Int->Int
s _=code{ccall time "I:I"ccall srand "I:I"
}
r::!Int->Int
r _=code{ccall rand "I:I"
}

Công dụng khác

Ngoài hai chức năng này, có lẽ là ứng dụng chính cho điều này trong môn đánh gôn, bạn có thể gọi bất kỳ chức năng được đặt tên nào (bao gồm nhưng không giới hạn ở mọi tòa nhà), lắp ráp tùy ý instruction <byte>và mã nhúng cho máy ABC.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.