是否可以用$替换括号?

时间:2017-06-08 11:53:52

标签: haskell

我有以下功能:

digits :: Int -> [Int]
digits n = go n []
    where go num acc
            | num < 10 = num : acc
            | otherwise = go (div num 10) (mod num 10 : acc)

是否可以将otherwise表达式中的括号替换为$

2 个答案:

答案 0 :(得分:8)

问题

您无法使用$$的目的是使函数应用程序尽可能无法绑定,而不是绑定最紧密的正常函数应用程序,

> :i $
($) :: (a -> b) -> a -> b
infixr 0 $

(删除了一些不相关的东西......)

此处,infixr表示运算符 r ight关联,而infixl表示运算符 l eft associative 。 0表示运算符的优先级。 0绑定最紧,9绑定最紧密。

如果我们写go $ div num 10 $ mod num 10 : acc,则会将其解释为go (div num 10 (mod num 10 : acc)),即:传递mod num 10 : acc作为div的第三个参数,以及应用div的结果}作为go的唯一参数。

解决方案:(&)运算符

而不是使用左侧的美元符号$,而是使用&

> :i &
(&) :: a -> (a -> b) -> b       -- Defined in `Data.Function'
infixl 1 &

现在我们得到:

import Data.Function ((&))

digits :: Int -> [Int]
digits n = go n []
    where go num acc
            | num < 10 = num : acc
            | otherwise = div num 10 & go $ mod num 10 : acc

解决方案:应用go infix

您还可以使用go infix:

digits :: Int -> [Int]
digits n = go n []
    where go num acc
            | num < 10 = num : acc
            | otherwise = div num 10 `go` (mod num 10 : acc)

在这种情况下,需要右侧的括号,因为(:)也是中缀并干扰go

使用哪种解决方案

在我看来,如果你可以使用没有括号的中缀应用程序,那就这样做吧。如果在任何一侧使用括号,例如:div num 10 `go` (mod num 10 : acc),则仍有理由使用中缀。这主要是由于可读性,因为普通读者可能不熟悉&。这种表示法(可能)不常用,这就是为什么普通读者不熟悉它(因此我们有一个循环......)。

关于$$

的用法

我相信Alexey Romanov的运营商$$也非常整洁。不幸的是,它遇到了与&一样的问题:缺乏熟悉感。希望他的运营商可以在适当的时候添加到Data.Function,也许我们可以扩展我们的工具箱。

答案 1 :(得分:8)

除了@Centril提到的答案之外,你只能替换第二对:

go (div num 10) $ mod num 10 : acc

或两者,但是你需要在不同的地方使用括号:

(go $ div num 10) $ mod num 10 : acc

或声明另一个运算符,如$但左联合:

f $$ x = f x
infixl 0 $$

go $$ div num 10 $$ mod num 10 : acc