Qual é a lógica por trás do uso de diferentes setas (- -) em Haskell?

5

Eu tenho pensado sobre o design da linguagem ultimamente, e lendo algumas das novas coisas em Haskell (sempre uma boa fonte de inspiração). Estou impressionado com os muitos usos estranhos dos operadores de <- e -> da esquerda à esquerda.

Eu acho que os muitos usos diferentes vem da arte anterior em matemática e outras linguagens sobre a sintaxe da seta, mas há alguma outra razão para não tentar tornar o uso mais consistente ou claro? Talvez eu só não esteja vendo o quadro geral?

A seta para a direita é usada como um construtor de tipo para funções, o separador entre argumento e corpo de expressões lambda, separador para instruções case e é usado em visualizações de padrão, que possuem o formato (e -> p) .

A seta para a esquerda é usada na notação do como algo semelhante à vinculação variável, em compreensões de lista para a mesma (suponho que sejam iguais, pois as abrangências de lista se parecem com blocos do condensados) e guardas de padrão, que têm o formato (p <- e) .

Agora, os últimos exemplos de cada flecha são apenas bobos! Eu entendo que guardas e visões servem a propósitos diferentes, mas eles têm uma forma quase idêntica, exceto que um é o espelho do outro! Eu também sempre achei estranho que as funções regulares são definidas com = , mas lambdas com -> . Por que não usar a flecha para ambos? Ou os iguais para ambos?

Ele também fica bem estranho quando você considera que, para comparar um valor calculado com uma constante, há quase meia dúzia de maneiras de fazer isso:

test x = x == 4

f     x = if test x then g x else h x

f'    4 = g 4
f'    x = h x

f''   [email protected](test -> true) = g x
f''   _ = h x

f'''  x | true <- test x = g x
        | otherwise = h x

f'''' x = case (x) of 
          4 -> g x
          _ -> h x

A variedade é o tempero do código-fonte, certo?

    
por CodexArcanum 28.08.2014 / 23:55
fonte

2 respostas

5

I've also always found it kind of odd that regular functions are defined with = but lambdas with ->. Why not use the arrow for both? Or the equals for both?

O símbolo de igualdade faz sentido para definições de função nomeadas porque afirma que aplicar a função nomeada aos seus argumentos é equivalente a avaliar o lado direito da equação. Definir lambdas dessa maneira não faz sentido notacionalmente: x = x + 1 implica x é igual ao seu sucessor, o que não pode ser verdade.

The left arrow gets used in do notation as something similar to variable binding, in list comprehensions for the same (I'm assuming they are the same, as list comprehensions look like condensed do blocks), and in pattern guards, which have the form (p <- e).

Todas essas construções ligam uma nova variável. Usar = aqui também não faria muito sentido, porque uma instrução como x = x + 1 implica que x se refere à mesma coisa em ambos os lados. Uma ligação variável introduz um novo x que é diferente de qualquer x que possa ocorrer no lado direito.

Uma alternativa seria usar apenas -> e colocar a variável à direita, mas acredito que posicioná-la à esquerda é objetivamente mais legível em culturas que são lidas da esquerda para a direita. Você digitaliza o texto movendo os olhos pela margem esquerda e, assim, colocando todas as variáveis à esquerda eles mais fáceis de encontrar. E embora ter dois símbolos diferentes para ligações variáveis possa não parecer consistente, há consistência na posição da variável que fica vinculada; está sempre à esquerda.

Isso deixa a questão de por que <- é oposto a outro símbolo como := . Eu não sei, mas posso adivinhar. Veja como é o código monádico desugared:

[1, 2, 3] >>= \xs -> map (*2) xs

Considerando que >>= com seus argumentos trocados é chamado =<< , provavelmente parecia natural usar uma seta virada para a esquerda.

    
por 11.03.2015 / 15:14
fonte
1

O operador <- é usado de duas maneiras, conforme descrito em Haskell operadores :

  1. Gerador de compreensão de lista;
  2. Operador de atribuição única em do-constr.

As compreensões de lista são açúcar sintático, como a expressão

import Data.Char (toUpper)

[toUpper c | c <- s]

onde s :: String é uma string como "Hello". Strings in Haskell são listas de caracteres; o gerador c <- s alimenta cada caractere de s da expressão à esquerda toUpper c , criando uma nova lista. O resultado dessa compreensão da lista é "OLÁ". (Claro que, neste exemplo simples, você escreveria apenas map toUpper s .)

Nas primeiras versões do Haskell, a sintaxe de compreensão estava disponível para todas as mônadas. Mais tarde, a sintaxe de compreensão foi restrita a listas. Como as listas são uma instância de mônadas, você pode obter compreensão da lista em termos de notação.

Por causa disso, vários programadores do Haskell consideram a compreensão da lista desnecessária agora.

O exemplo acima pode ser traduzido para listar a mônada da seguinte forma:

do c <- s return (toUpper c)

Para mais informações, consulte Compreensão da lista .

    
por 11.03.2015 / 12:50
fonte