Pergunta

Eu tenho um problema com o escopo de Haskell em definições where. Quando eu tenho o seguinte f função, onde eu quero passar o x ao f1 função definida localmente sem explicitamente usando-o como um parâmetro, eu recebo um erro dizendo que o tipo de x é incompatível com a da saída do f1, embora deva ser o mesmo:

f :: Eq a => a -> [a]
f x = f1 x
    where
        f1 :: Eq a => a -> [a]
        f1 y = [ x, y ]

O erro é o seguinte:

    Couldn't match expected type `a1' against inferred type `a'
      `a1' is a rigid type variable bound by
           the type signature for `f1' at test.hs:4:11
      `a' is a rigid type variable bound by
          the type signature for `f' at test.hs:1:8
    In the expression: x
    In the expression: [x, y]
    In the definition of `f1': f1 y = [x, y]
Failed, modules loaded: none.

Quando eu no entanto passar o x como um parâmetro adicional, como eu fiz no código a seguir com o g função, ele funciona muito bem:

g :: Eq a => a -> [a]
g x = g1 x x
    where
        g1 :: Eq a => a -> a -> [a]
        g1 x y = [ x, y ]

Existe uma maneira de fazer o a tipo em f compatível à a tipo (ou a1) em f1?

Foi útil?

Solução

O problema com o seu código é o escopo localmente assinatura de tipo f1. Ele especifica que F1 pode tomar qualquer tipo

f1 :: Eq a => a -> [a]

Mesmo que esta é uma função local, você generalizado esta função para ser capaz de tomar um tipo que não vai existir dentro de f, qualquer que seja esta função recebe tem que vir de f, então a assinatura de tipo é desnecessária.

Apenas remover a assinatura de tipo f1.

Edit: Leia o meu post de volta para mim, é um pouco incerto. um em f1 é um tipo parametrizado que pode levar nada, mas os argumentos passados ??para ele já está ligado no f. Portanto, esta função só pode receber o que sua função pai recebe, a assinatura de tipo que você está dando ele quebra essa regra. Esperança de que é um pouco mais clara.

Outras dicas

Dave está logo acima. Outra maneira de pensar sobre isso é que, apesar de ambos os tipo assinaturas referem-se ao a variável, não é realmente o mesmo tipo de variável. Na notação Haskell-prime, ambas as assinaturas podem ser mais explicitamente escrito como:

forall a . Eq a => a -> [a]

o que significa que para ambos funções, eles podem aceitar um argumento de qualquer tipo (dentro Eq). Isso obviamente não é o caso aqui. No padrão Haskell 98, a única opção é renunciar a assinatura tipo para f1. Mas GHC (e outros?) Apoio lexically variáveis ??de tipo de escopo . Então, você poderia escrever

{-# LANGUAGE ScopedTypeVariables #-}

f :: forall a. Eq a => a -> [a]
f x = f1 x
    where
        f1 :: a -> [a]
        f1 y = [ x, y ]

e que iria funcionar bem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top