Dicas para jogar golfe em F #

21

Que dicas gerais você tem para jogar golfe em F #? Estou procurando idéias que possam ser aplicadas aos problemas de código de golfe em geral que sejam pelo menos um pouco específicos para F # (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.

ProgramFOX
fonte

Respostas:

9

Use em functionvez de matchquando possível; ele salvará 6 caracteres para variáveis ​​de 1 caractere:

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

vs

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

Também pode substituir qualquer correspondência de padrão para salvar consistentemente 1 caractere:

match a with|          // ... (13 chars)
a|>function|           // ... (12 chars)
(function| (* ... *))a // (12 chars)
Jwosty
fonte
8

Precisa usar um método na variável para o qual você ainda não restringiu o tipo? Apenas compare-o com um literal do tipo que você deseja que seja e jogue fora o resultado para anotar o tipo dessa variável:

let f (x:string)=x.Length
let f x=x="";x.Length
Jwosty
fonte
7

Use a notação de prefixo para operadores de infixo quando puder - isso evitará que você precise definir uma função para usá-los.

Por exemplo, você pode ativar isso:

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

nisso:

List.map((+)2)[1;1;2;3;5;8]
Roujo
fonte
11
Eu uso aqui obrigado!
aloisdg diz Reinstate Monica
5

Desconstrução de tupla

Caso não consiga usar variáveis, use a desconstrução da tupla em vez de várias expressões let

let a,b ="",[]

ao invés de

let a=""
let b=[]

Lendo de stdin

A biblioteca principal do F # define um alias para System.Console.Inchamado stdin. Isso permite que você leia a entrada.

// Signature:
stdin<'T> :  TextReader

TextReader no msdn

A grande vantagem, além de ser mais curta do que Consoleé, não é necessário abrir o System

Iterando sobre String

string é basicamente um char seq, isso permite que você use Seq.mapdiretamente com strings. Também é possível usá-los em compreensões[for c in "" do]

Mutables / células de referência

O uso de células de referência nem sempre é mais curto, pois toda operação de leitura vem com um caractere adicional para apagar a célula.

Dicas gerais

  • É possível escrever a match .. withlinha completa

    function|'a'->()|'b'->()|_->()
    
  • Não há necessidade de espaço em branco antes e depois de caracteres não alfanuméricos.

    String.replicate 42" "
    if Seq.exists((<>)'@')s then
    if(Seq.exists((<>)'@')s)then
    
  • Caso você precise colocar uma string com espaços à esquerda ou à direita, você pode usar sinalizadores [s] printf [n] para isso.

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

    Módulo Core.Printf

Brunner
fonte
4

Use id em vez de x-> x

id é um operador que representa a função de identidade.

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

pode ser escrito

let u x=x|>Seq.countBy id

fonte

Eu uso aqui

aloisdg diz Restabelecer Monica
fonte
3

Eta-conversão para funções

Muito obrigado a Laikoni por esta dica em uma das minhas soluções .

Considere uma função para, digamos, somar uma sequência com 3 para letras maiúsculas e 1 para todos os outros caracteres. Tão:

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

Por conversão eta, isso pode ser reescrito como:

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

e chamado da mesma maneira que antes:

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

O operador de composição direta da função >>

Agora, suponha que nosso desafio original seria somar uma sequência com 3 para letras maiúsculas e 1 para letras minúsculas, e todos os outros caracteres são excluídos.

Podemos escrever isso como:

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

Podemos usar o operador de composição direta ( >>) para encadear as duas funções ( Seq.filtere Seq.sumBy) juntas. Com a conversão eta, a definição da função se tornaria:

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

Chris Smith fez um ótimo artigo sobre o >>operador em seu blog do MSDN .

Ciaran_McCarthy
fonte
2

Quando possível, Seqé menor que List:

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

é um char mais curto ...

thinkbeforecoding
fonte
2

Evite parênteses ao usar um parâmetro e na tupla

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

pode ser escrito

let f = [0,1;1,4]|>Seq.map fst
printfn "%A" f
aloisdg diz Restabelecer Monica
fonte
11
Você também não precisa () em torno das tuplas: deixe f = [0,1; 1,4] |> Seq.map fst
thinkbeforecoding
11
Obrigado. Atualizada.
aloisdg diz Reinstate Monica
2

Preferir nova string de linha sobre "\ n"

Isso começará a render até mesmo um único caractere de nova linha no seu código. Um caso de uso pode ser:

(18 bytes)

string.Concat"\n"

(17 bytes)

string.Concat"
"

Inspirado na resposta de Chiru para es6 .

Utilizado aqui

aloisdg diz Restabelecer Monica
fonte
1

Use .NET

O .NET oferece muitos bons recursos. O F # pode usá-los, então não os esqueça!

Exemplo:

open System.Linq

Pode ser útil!

aloisdg diz Restabelecer Monica
fonte
1

Use lambdas para salvar um byte. Por exemplo, isto:

let f x=x*x

Pode ser expresso como este:

fun x->x*x
dana
fonte
1

Use para ... para em vez de para ... para percorrer um intervalo

for i in[0..2]
for i=0 to 2
aloisdg diz Restabelecer Monica
fonte
1

A modulepalavra-chave pode ser usada para encurtar os nomes dos módulos quando usados ​​repetidamente. Por exemplo:

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

pode se tornar

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

Isso é mais útil para programas mais longos, em que os métodos do módulo são usados ​​repetidamente (e devem ser totalmente nomeados toda vez porque possuem o RequireQualifiedAccessmodificador) e permite reduzir alguns caracteres, especialmente quando é mais útil usar uma matriz CLR regular (por exemplo, mutabilidade ) que um F # seqou list.

LSM07
fonte