Вопрос

В следующем фрагменте вы можете увидеть две мои функции Collatz, которые я написал в Haskell. Для рекурсивного применения я использовал скобки в первом примере (Collatz), чтобы получить правильный приоритет.

Поскольку я только что выучил приложение для функций с $, я попытался переписать функцию (коллатц), используя эту вещь. Однако я сталкиваюсь с следующей ошибкой:

Не мог соответствовать ожидаемому типу `[a] 'против предполагаемого типа` a1 -> [a1]' во втором аргументе «(:)», а именно «коллатц» в первом аргументе «($)», а именно `n: collatz '' в выражении: n: collatz '$ n` div` 2

collatz :: (Integral a) => a -> [a]

collatz 1 = [1]

collatz n | even n    = n : collatz (n `div` 2)
          | otherwise = n : collatz (n * 3 + 1)

collatz' :: (Integral a) => a -> [a]

collatz' 1 = [1]

collatz' n | even n    = n : collatz' $ n `div` 2
           | otherwise = n : collatz' $ n * 3 + 1

Мне странно, что это не сработало. Итак, я попробовал аналогичный пример, который сработал:

True : [even $ 3 `div` 3]

Я бы признателен, если бы кто -то мог взглянуть на это и сказать мне, что я делаю не так.

Это было полезно?

Решение

$ Тогда имеет более низкий приоритет : (а также все остальное), поэтому ваша функция анализирует как

(n : collatz') $ (n `div` 2)

Это приводит к вашей ошибке типа. Второй аргумент : Ожидает список, но вместо этого вы выполняете функцию Collatz.

Если вы все еще хотите избежать скобок вокруг 3n+1 части, вы можете сделать что -то вроде следующего

(n:) . collatz' $ n `div` 2
n : (collatz' $ n `div` 2)

Хотя это не обязательно чище, то оригинал. Если вам интересно, (n:) В первом примере - синтаксический сахар для \x -> n : x

Другие советы

Поскольку другие объяснили, в чем проблема, я подумал, что объясню, как вы могли бы понять это самостоятельно. (Учите человека ловить рыбу и так далее ...)

Обратите внимание на эту часть сообщения об ошибке:

В первом аргументе «($)», а именно «n: collatz»

Это подсказка в том, чтобы заметить, что это проблема приоритета. GHC говорит вам, что n : collatz' был проанализирован как первый аргумент $, пока вы ожидали, что первый аргумент будет просто collatz'.

На этом этапе я обычно запускаю GHCI и проверяю приоритеты, включенные с использованием :info Команда:

> :info :
data [] a = ... | a : [a]   -- Defined in GHC.Types
infixr 5 :
> :info $
($) :: (a -> b) -> a -> b   -- Defined in GHC.Base
infixr 0 $

В нем говорится, что достоверность : 5, в то время как приоритет $ 0, что объясняет, почему : является обязательным «плотнее», чем $.

: связывается более сильно, чем $. Анкет Рассмотреть возможность

Prelude> let f x = [x]
Prelude> 1 : f 2
[1,2]
Prelude> 1 : f $ 2

<interactive>:1:5:
    Couldn't match expected type `[a0]' with actual type `t0 -> [t0]'
    In the second argument of `(:)', namely `f'
    In the expression: 1 : f
    In the expression: 1 : f $ 2

Обратите внимание на «выражение» 1 : f найдено парсером; он видит (1 : f) $ 2 скорее, чем 1 : (f $ 2).

Как заявил @missingno, это проблема приоритета оператора. Вы можете переписать это так

collatz' n | even n    = n : (collatz' $ n `div` 2)
           | otherwise = n : (collatz' $ n * 3 + 1)

Но это, очевидно, не покупает вас много, потому что у вас все еще есть скобка.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top