Haskell: Function application with $

后端 未结 4 1676
滥情空心
滥情空心 2021-01-11 15:00

In the following snippet, you can see my two collatz functions I wrote in Haskell. For the recursive application I used parentheses in the first example (collatz) to get the

相关标签:
4条回答
  • 2021-01-11 15:04

    As @missingno stated, it's an operator precedence problem. You could rewrite it like this

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

    But that obviously doesn't buy you much, because you still have parenthesis.

    0 讨论(0)
  • 2021-01-11 15:07

    : binds more strongly than $. Consider

    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
    

    Note the "expression" 1 : f found by the parser; it sees (1 : f) $ 2 rather than 1 : (f $ 2).

    0 讨论(0)
  • 2021-01-11 15:26

    Since others have explained what the problem is, I figured I'll explain how you could have figured this out on your own. (Teaching a man to fish and so on...)

    Note this part of the error message:

    In the first argument of '($)', namely 'n : collatz''

    That's the clue to noticing that this is a precedence problem. GHC is telling you that n : collatz' was parsed as the first argument of $, while you were expecting the first argument to be just collatz'.

    At this point, I usually fire up GHCi and check the precedences involved using the :info command:

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

    It says that the precendence of : is 5, while the precedence of $ is 0, which explains why the : is binding "tighter" than the $.

    0 讨论(0)
  • 2021-01-11 15:28

    $ has lower precedence then : (and also anything else) so your function is parsing as

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

    This leads to your type error. The second argument of : expects a list but you are passing the collatz function instead.

    If you still want to avoid the parenthesis around the 3n+1 part you can do something like the following

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

    although these are not necessarily cleaner then the original. In case you are wondering, the (n:) in the first example is a syntactic sugar for \x -> n : x

    0 讨论(0)
提交回复
热议问题