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)
но это, очевидно, не купит вам много, потому что у вас все еще есть скобки.