2009-11-30 1 views
13

У меня проблема с областью Haskell в определениях where. Когда у меня есть следующая функция f, где я хочу передать x локально определенной функции f1, не используя ее в качестве параметра, я получаю сообщение об ошибке, что тип x несовместим с типом f1, хотя она должна быть такой же:Haskell просматривает определения вложенных функций, используя где

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

ошибка заключается в следующем:

 
    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. 

Когда я однако передать x в качестве дополнительного параметра, как я сделал в следующем коде с помощью функции g, он отлично работает:

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

Есть ли способ, чтобы сделать тип a в f совместимом тип a (или a1) в f1?

+1

Хотя это очень хорошая практика для сахара вашего кода с сигнатурами типа лота, за исключением чрезвычайно тривиальных частей, я не вижу причин для использования в них локальных функций с сахаром. Понятно, что такое подпись типа, а для таких тривиальных функций вы теряете больше в читаемости, чем получаете. – Rayne

+1

Ну, фактическая функция была более сложной, я просто сводил ее к простому примеру, чтобы моя фактическая проблема стала ясна. – poke

ответ

11

Проблема с вашим кодом - это локализованная подпись типа f1. Он указывает, что f1 может принимать любой тип

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

Даже если это локальная функция, вы обобщили эту функцию, чтобы быть в состоянии принять тип, который не будет существовать в е, чем бы эта функция принимает Должен прибыть из f, поэтому подпись типа не нужна.

Просто удалите подпись типа f1.

Редактировать: прочитайте мой пост назад к себе, это немного неясно. a в f1 является параметризованным типом, который может принимать что угодно, но переданные ему аргументы уже связаны по f. Таким образом, эта функция может получать только то, что получает ее родительская функция, подпись типа, которую вы даете ей, нарушает это правило. Надеюсь, это немного более ясно.

+0

Да, это работает, спасибо :) Хотя он все еще оставляет опасение, неспособное явно вводить функцию 'f1' (я исхожу из более строгих языков), но ну, пока ничего не ломается;) – poke

+5

Poke: Проблема здесь в том, что Haskell является более строгим, чем вы ожидаете. Ваша оригинальная сигнатура типа для 'f1' указала, что аргумент может быть чем-то принадлежащим к классу «Eq», но компилятор правильно понял, что аргумент, переданный в «f1», фактически должен был быть тем, что было передано «f». Удаление сигнатуры типа для «f1» не ослабляет строгость шрифта. Это позволяет компилятору выводить текст для вас. –

13

Dave находится прямо выше. Другой способ подумать об этом состоит в том, что, хотя обе подписи вашего типа относятся к переменной a, это не та же переменная типа. В Haskell-премьер-нотации, обе подписи могут быть более явным образом записать в виде:

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

означает, что для оба функций, они могут принять аргумент любого типа (в формуле). Это, очевидно, не так. В стандартном Haskell 98 единственный вариант - отказаться от сигнатуры типа для f1. Но GHC (и другие?) Поддерживают lexically scoped type variables. Таким образом, вы можете написать

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

и все будет работать нормально.

Смежные вопросы