Lema: Assumindo a eta-equivalência, temos isso (\x -> ⊥) = ⊥ :: A -> B
.
Prova: ⊥ = (\x -> ⊥ x)
por eta-equivalência e (\x -> ⊥ x) = (\x -> ⊥)
por redução no lambda.
O relatório Haskell 2010, seção 6.2 especifica a seq
função por duas equações:
seq :: a -> b -> b seq ⊥ b = ⊥ seq ab = b, se a ≠ ⊥
Ele então afirma "Como conseqüência, ⊥ não é o mesmo que \ x -> ⊥, pois seq pode ser usado para distingui-los."
Minha pergunta é: isso é realmente uma consequência da definição de seq
?
O argumento implícito parece ser que seq
seria incontestável se seq (\x -> ⊥) b = ⊥
. No entanto, não consegui provar que isso seq
seria incontestável. Parece-me que tal seq
é monótono e contínuo, o que o coloca no domínio de ser computável.
Um algoritmo que implementa como seq pode funcionar tentando procurar por algum x
local f x ≠ ⊥
, enumerando o domínio def
começar com ⊥. Embora essa implementação, mesmo que seja possível, fique bastante complicada quando queremos fazer seq
polimórficos.
Existe uma prova de que não há computável seq
que identifica (\x -> ⊥)
com ⊥ :: A -> B
? Como alternativa, há alguma construção do seq
que se identifica (\x -> ⊥)
com ⊥ :: A -> B
?
fonte
seq
seq
Observe que a especificação para a
seq
qual você cita não é sua definição. Para citar o relatório Haskell "A função seq é definida pelas equações : [e depois pelas equações que você fornecer]".Esse comportamento violaria a especificação de
seq
.É importante ressaltar que, uma vez que
seq
é polimórfico,seq
não pode ser definido em termos de desconstrutores (projeções / correspondência de padrões etc.) em um dos dois parâmetros.Se
seq' (\x -> ⊥) b
, poder-se-ia pensar que poderíamos aplicar o primeiro parâmetro (que é uma função) a algum valor e depois sair. Mas,seq
nunca é possível identificar o primeiro parâmetro com um valor de função (mesmo que seja um para algum usoseq
) devido ao seu tipo polimórfico paramétrico. Parametricidade significa que não sabemos nada sobre os parâmetros. Além disso,seq
nunca pode tomar uma expressão e decidir "é este ⊥?" (cf. o problema da parada),seq
pode apenas tentar avaliá-lo, e ele próprio diverge para ⊥.O que
seq
faz é avaliar o primeiro parâmetro (não totalmente, mas a "forma de cabeça fraca normal" [1], ou seja, ao mais alto construtor), em seguida, retornar o segundo parâmetro. Se o primeiro parâmetro for⊥
(ou seja, um cálculo não-terminativo), avaliá-lo fazseq
com que não termine e, portanto,seq ⊥ a = ⊥
,.[1] Teoremas livres na presença de seq - Johann, Voigtlander http://www.iai.uni-bonn.de/~jv/p76-voigtlaender.pdf
fonte
f : forall a . a -> T
(ondeT
está outro tipo),f
não é possível aplicar nenhum desconstrutor ao seu primeiro argumento, pois ele não sabe quais desconstrutores aplicar. Não podemos fazer um "caso" em tipos. Eu tentei melhorar a resposta acima (inclusive citando informações sobre comoseq
avaliar a forma normal da cabeça).Samson Abramsky considerou esta questão há muito tempo e escreveu um artigo chamado " The Lazy Lambda Calculus ". Portanto, se você deseja definições formais, é aqui que deve procurar.
fonte
Provando que λ x. Ω ≠ Ω in é um dos objetivos que Abramsky estabelece para sua teoria do cálculo preguiçoso de lambda (página 2 de seu trabalho , já citado por Uday Reddy), porque ambos estão em forma normal de cabeça fraca. Na definição 2.7, ele discute explicitamente que eta-redução λ x. M x → M geralmente não é válido, mas é possível se M terminar em todos os ambientes. Isso não significa que M deve ser uma função total - apenas que a avaliação de M deve terminar (reduzindo para um lambda, por exemplo).
Sua pergunta parece ser motivada por preocupações práticas (desempenho). No entanto, embora o Relatório Haskell possa ser menos que completamente claro, duvido que seja igual a λ x. Com ⊥ produziria uma implementação útil de Haskell; se implementa Haskell '98 ou não, é discutível, mas, dada a observação, fica claro que os autores pretendiam que fosse esse o caso.
Finalmente, como seq gerar elementos para um tipo de entrada arbitrário? (Eu sei que o QuickCheck define a classe arbitrária para isso, mas você não tem permissão para adicionar essas restrições aqui). Isso viola a parametridade.
Atualizado : não consegui codificar isso direito (porque não sou tão fluente em Haskel) e corrigir isso parece exigir
runST
regiões aninhadas . Tentei usar uma única célula de referência (na mônada do ST) para salvar esses elementos arbitrários, lê-los mais tarde e disponibilizá-los universalmente. A parametridade prova quebreak_parametricity
abaixo não pode ser definido (exceto retornando a parte inferior, por exemplo, um erro), enquanto pode recuperar os elementos que a seq proposta geraria.Devo admitir que estou um pouco confuso em formalizar a prova de parametridade necessária aqui, mas esse uso informal da parametridade é padrão em Haskell; mas aprendi com os escritos de Derek Dreyer que a teoria necessária está sendo rapidamente elaborada nos últimos anos.
Editar% s:
fonte
(\x -> writeSTRef cell (Just x) >> return x)
de entradas aleatórias não executa uma gravação na célula. Somente os comandos ST que fazem parte do passado sequenciadorunST
são executados. Da mesma forma, a execuçãomain = (putStrLn "Hello") `seq` (return ())
não imprime nada no visor.