简体   繁体   中英

$ does not always work in Haskell

Here is a Haskell code sample.

indentBrackets (c:rest) level
   | c=='('    = "\n" ++ (replicate level ' ') ++ [c]
                      ++ (indentBrackets rest (level+1))
   | c==')'    =  [c] ++ (indentBrackets rest (level-1))
   | c=='['    = "\n" ++ (replicate level ' ') ++ [c] 
                      ++ (indentBrackets rest (level+1))
   | c==']'    =  [c] ++ (indentBrackets rest (level-1))
   | otherwise =  [c] ++ (indentBrackets rest (level  ))

indentBrackets [] _ = ""

if I replace otherwise = [c] ++ (indentBrackets rest (level)) with otherwise = [c] ++ $ indentBrackets rest (level) , I get

src\\Main.hs:182:25: parse error on input `$'

Should not that be ok?

Yes, that should not be ok.

The $ operator is a perfectly ordinary infix operator: you can use it between two expressions (a function and its argument, respectively) or to form a section . The reason it is incorrect in

[c] ++ $ indentBrackets rest (level)   -- parse error on input `$'

is that the ++ operator is a perfectly ordinary infix operator: you can use it between two expressions (a prefix and its suffix, respectively) or to form a section . The trouble is that [c] ++ is not an expression.

If you are unadvisedly determined to use $ for this particular application, you can fix the problem by, indeed, making a section

([c] ++) $ indentBrackets rest (level)   -- should be fine

The extra set of brackets in ([c] ++) delimits an operator section, being an underapplied infix operator, here yielding the function still awaiting the suffix.

Note that you don't need parens or $ here at all : what you have is of the form

a ++ (f b (c))

Now, first, the parens around c do nothing, c is "atomical" anyway.

a ++ (f b c)

Next, remember how multiple arguments are handled in Haskell: Currying , ie

a ++ ((f b) c)

Let's use g = fb for a while...

a ++ (g c)

Ok, gc is a straightforward application, function / lambda-expression to value. Function application binds more tightly than any infix operator, so that's the same as

a ++ g c

Now bring back f

a ++ (f b) c

remove the currying brackets again, and you end up with

a ++ f b c

or, for your example,

[c] ++ indentBrackets rest level

If we apply it to your entire code:

indentBrackets (c:rest) level
   | c=='('    = "\n" ++ replicate level ' ' ++ [c]
                      ++ indentBrackets rest (level+1)
   | c==')'    =  [c] ++ indentBrackets rest (level-1)
   | c=='['    = "\n" ++ replicate level ' ' ++ [c] 
                      ++ indentBrackets rest (level+1)
   | c==']'    =  [c] ++ indentBrackets rest (level-1)
   | otherwise =  [c] ++ indentBrackets rest  level

Incidentally, I'd trim this down a bit:

indentBrackets (c:rest) level
   | c `elem` "(["  = "\n" ++ replicate level ' '
                        ++ c : indentBrackets rest (level+1)
   | c `elem` ")]"  =  c : indentBrackets rest (level-1)
   | otherwise =  c : indentBrackets rest  level

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM