Haskell: применение функции с $

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

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

не может соответствовать ожидаемому типу ' [a]' против выведенного типа 'a1 - > [a1]' во втором аргумент ` (:)', а именно 'collatz' в первом аргументе ' ( $ )', а именно ' 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]

4 ответов


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

(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 :
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)

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