Haskell просматривает определения вложенных функций, используя
У меня проблема с Haskell в определении where
. Когда у меня есть следующая функция f
, где я хочу передать x
в локально определенную функцию f1
без явного использования ее в качестве параметра, я получаю сообщение об ошибке, говоря, что тип x
несовместим с тот, который находится на выходе f1
, хотя он должен быть одним и тем же:
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
Проблема с вашим кодом - это сигнатура типа f1 с локальным охватом. Он указывает, что f1 может принимать любой тип
f1 :: Eq a => a -> [a]
Несмотря на то, что это локальная функция, вы обобщили эту функцию, чтобы иметь возможность принимать тип, который не будет существовать внутри f, независимо от того, что эта функция получает от HAS, из-за f, поэтому подпись типа не нужна.
Просто удалите подпись типа f1.
Изменить: прочитайте мой пост назад, я немного неясен. a в f1 является параметризованным типом, который может принимать что угодно, но переданные ему аргументы уже связаны по f. Таким образом, эта функция может получать только то, что получает ее родительская функция, подпись типа, которую вы даете ей, нарушает это правило. Надеюсь, что немного более ясно.
Ответ 2
Дэйв прямо выше. Другой способ думать о том, что хотя обе ваши сигнатуры типа ссылаются на переменную a
, на самом деле это не a
и та же переменная типа. В нотации простого числа Хаскелла обе подписи могут быть записаны более явно как:
forall a. Eq a => a → [a]
Это означает, что для обеих функций они могут принимать аргументы любого типа (в уравнении). Это явно не тот случай. В стандартном Haskell 98 единственный вариант - отказаться от подписи типа для f1
. Но GHC (и другие?) Поддерживают переменные типа с лексической областью. Чтобы ты мог написать
{-# LANGUAGE ScopedTypeVariables #-}
f :: forall a. Eq a => a -> [a]
f x = f1 x
where
f1 :: a -> [a]
f1 y = [ x, y ]
и это будет работать нормально.