Wskazówki do gry w golfa w F #

21

Jakie masz ogólne wskazówki na temat gry w golfa w F #? Szukam pomysłów, które można by zastosować do problemów z golfem w kodzie, które są przynajmniej nieco specyficzne dla F # (np. „Usuń komentarze” nie jest odpowiedzią). Proszę zamieścić jedną wskazówkę na odpowiedź.

ProgramFOX
źródło

Odpowiedzi:

9

Użyj functionzamiast, matchgdy to możliwe; zapisze 6 znaków dla zmiennych 1-znakowych:

let f=function // ... (14 chars)

vs

let f x=match x with // ... (20 chars)

Może również zastąpić dowolne dopasowanie wzorca, aby konsekwentnie zapisywać 1 znak:

match a with|          // ... (13 chars)
a|>function|           // ... (12 chars)
(function| (* ... *))a // (12 chars)
Jwosty
źródło
8

Potrzebujesz użyć metody na zmiennej, dla której nie ograniczyłeś jeszcze typu? Po prostu porównaj go z literałem typu, który chcesz, a następnie wyrzuć wynik, aby opisać typ tej zmiennej:

let f (x:string)=x.Length
let f x=x="";x.Length
Jwosty
źródło
7

Jeśli to możliwe, używaj notacji prefiksowej dla operatorów infix - pozwoli to uniknąć konieczności definiowania funkcji, aby z nich korzystać.

Na przykład możesz to zmienić:

List.map(fun i->i+2)[1;1;2;3;5;8]

zaangażowany w to:

List.map((+)2)[1;1;2;3;5;8]
Roujo
źródło
1
Używam go tutaj, dziękuję!
aloisdg mówi Przywróć Monikę
5

Dekonstrukcja krotkowa

Jeśli nie możesz przejść do korzystania ze zmiennych, użyj dekonstrukcji krotek zamiast wielu wyrażeń let

let a,b ="",[]

zamiast

let a=""
let b=[]

Czytanie ze standardowego

Biblioteka podstawowa F # definiuje alias dla System.Console.Inwywoływanej stdin. Umożliwiają one odczytywanie danych wejściowych.

// Signature:
stdin<'T> :  TextReader

TextReader na msdn

Dużą zaletą jest to, że jest krótszy niż Consoleobecnie, nie trzeba też otwierać Systemu

Iterowanie po sznurku

string jest w zasadzie a char seq, to pozwala ci używać Seq.mapbezpośrednio z stringami. Można je również wykorzystać w zrozumieniu[for c in "" do]

Zmienne / komórki referencyjne

Korzystanie z komórek referencyjnych nie zawsze jest krótsze, ponieważ każda operacja odczytu wiąże się z dodatkowym znakiem wykreślającym komórkę.

Ogólne wskazówki

  • Można napisać cały match .. withwiersz

    function|'a'->()|'b'->()|_->()
    
  • Nie ma potrzeby używania białych znaków przed i po znakach nie alfanumerycznych.

    String.replicate 42" "
    if Seq.exists((<>)'@')s then
    if(Seq.exists((<>)'@')s)then
    
  • W przypadku, gdy chcesz wstawić lewy lub prawy ciąg znaków ze spacjami, możesz użyć do tego flag [s] printf [n].

    > sprintf "%20s" "Hello, World!";;
    val it : string = "       Hello, World!"
    

    Moduł Core.Printf

Brunner
źródło
4

Użyj id zamiast x-> x

id to operator oznaczający funkcję tożsamości.

let u x=x|>Seq.countBy (fun x->x)

można napisać

let u x=x|>Seq.countBy id

źródło

Korzystam z tego tutaj

aloisdg mówi Przywróć Monikę
źródło
3

Eta-konwersja funkcji

Ogromne podziękowania dla Laikoni za tę wskazówkę w jednym z moich rozwiązań .

Rozważ funkcję, powiedzmy, sumowania ciągu 3 dla wielkich liter i 1 dla wszystkich innych znaków. Więc:

let counter input = Seq.sumBy (fun x -> if Char.IsUpper x then 3 else 1) input

Przez eta-konwersję można to zapisać ponownie jako:

let counter = Seq.sumBy (fun x -> if Char.IsUpper x then 3 else 1)

i wywoływane w taki sam sposób jak poprzednio:

counter "Hello world!" |> printfn "%i"

Funkcja operatora kompozycji do przodu >>

Załóżmy teraz, że naszym pierwotnym wyzwaniem byłoby zsumowanie ciągu 3 dla wielkich liter i 1 dla małych liter, a wszystkie inne znaki są wykluczone.

Możemy to napisać jako:

let counter input = Seq.filter Char.IsLetter input |> Seq.sumBy (fun x -> if Char.IsUpper x then 3 else 1)

Możemy użyć operatora kompozycji do przodu ( >>), aby połączyć dwie funkcje ( Seq.filteri Seq.sumBy) razem. W przypadku konwersji eta definicja funkcji wyglądałaby następująco:

let counter = Seq.filter Char.IsLetter >> Seq.sumBy (fun x -> if Char.IsUpper x then 3 else 1)

Chris Smith napisał świetną recenzję dla >>operatora na swoim blogu MSDN .

Ciaran_McCarthy
źródło
2

Jeśli Seqto możliwe, jest krótszy niż List:

[[1];[2;3];[4];[5]|>List.collect
[[1];[2;3];[4];[5]|>Seq.collect

jest o jeden char krótszy ...

thinkbeforecoding
źródło
2

Unikaj nawiasów, gdy używasz jednego parametru i na krotce

let f = [(0,1);(1,4)]|>Seq.map(fst)
printfn "%A" f

można napisać

let f = [0,1;1,4]|>Seq.map fst
printfn "%A" f
aloisdg mówi Przywróć Monikę
źródło
1
Nie potrzebujesz też () wokół krotek: niech f = [0,1; 1,4] |> Seq.map fst
thinkbeforecoding
1
Dziękuję Ci. zaktualizowane.
aloisdg mówi Przywróć Monikę
2

Preferuj nowy ciąg wiersza nad „\ n”

Zacznie się to opłacać nawet w jednym nowym znaku wiersza w kodzie. Jednym przypadkiem użycia może być:

(18 bajtów)

string.Concat"\n"

(17 bajtów)

string.Concat"
"

Zainspirowany odpowiedzią Chiru na es6 .

Użyto tutaj

aloisdg mówi Przywróć Monikę
źródło
1

Użyj .NET

.NET oferuje wiele fajnych wbudowanych funkcji. F # może ich używać, więc nie zapomnij o nich!

Przykład:

open System.Linq

To może być pomocne!

aloisdg mówi Przywróć Monikę
źródło
1

Użyj lambdas, aby zapisać bajt. Na przykład:

let f x=x*x

Można to wyrazić następująco:

fun x->x*x
dana
źródło
1

Użyj dla ... aby zamiast dla ... w, aby przejść zasięg

for i in[0..2]
for i=0 to 2
aloisdg mówi Przywróć Monikę
źródło
1

Słowo modulekluczowe może być użyte do skrócenia nazw modułów, gdy są używane wielokrotnie. Na przykład:

Array.fold ...
Seq.iter ...
List.map ...

może zostać

module A=Array
A.fold ...
module S=Seq
S.iter ...
module L=List
L.map ...

Jest to bardziej przydatne w przypadku dłuższych programów, w których metody modułowe są używane wielokrotnie (i muszą być za każdym razem pełne nazwy, ponieważ mają RequireQualifiedAccessmodyfikator), i pozwala na wyłączenie kilku znaków, szczególnie gdy bardziej użyteczne jest użycie zwykłej tablicy CLR (np. Zmienność ) niż F # seqlub list.

LSM07
źródło