Haskell $运算符:为什么这不起作用?

gog*_*urt 0 haskell

Haskell Programming from First Principles一书中,有一个练习告诉我们编写一个函数,它接受一个带有空格的字符串,用空格分割它,并将非空间块加载到一个字符串列表中.我的第一次尝试是:

splitString :: String -> [String]
splitString str
  | str == "" = []
  | otherwise = takeWhile (/=' ') str : splitString $ drop 1 $ dropWhile (/=' ') str
Run Code Online (Sandbox Code Playgroud)

现在这不编译.如果我将第一个($)(右后splitString)替换为相应的括号对,如下所示:

takeWhile (/=' ') str : splitString (drop 1 $ dropWhile (/=' ') str)
Run Code Online (Sandbox Code Playgroud)

然后它工作.根据我迄今为止所学到的关于($)的内容,不应该两者相等吗?($)是正确的联想,因此在我看来应该发生的事情是什么

  1. dropWhile (/=' ') str 首先评估
  2. drop 1 (dropWhile (/=' ') str) 是下一个
  3. 然后结果传递给splitString.

相反,我得到一个错误,从ghc它说

Couldn't match expected type ‘[Char] -> [String]’
            with actual type ‘[[Char]]’
The first argument of ($) takes one argument,
but its type ‘[[Char]]’ has none
Run Code Online (Sandbox Code Playgroud)

我可以通过"($)的第一个论点"看到它splitString,但我对这个陈述感到困惑

but its type `[[Char]]` has none
Run Code Online (Sandbox Code Playgroud)

应该是的意思.

Eri*_*ikR 8

如果您添加如下所示的parens,您的代码将起作用:

...
  | otherwise = takeWhile (/=' ') str : ( splitString $ drop 1 $ dropWhile (/=' ') str )
--                                     ^^^                                            ^^^                                                                                        
Run Code Online (Sandbox Code Playgroud)

否则Haskell将else子句解释为:

( takeWhile (/=' ') str : splitString )
    $ drop 1
    $ dropWhile (/= ' ') str
Run Code Online (Sandbox Code Playgroud)

更新

您在评论中提到的版本:

     takeWhile (/= ' ') str : splitString ( ... )
--   \__ a __/ \_ b _/   c  : \___ d ___/ \_ e _/
Run Code Online (Sandbox Code Playgroud)

具有a b c : d eHaskell总是解释的形式,(a b c) : (d e)因为:它是唯一出现表达式的中缀运算符.

当你有类似的东西:

    a b c : d e $ f $ g
Run Code Online (Sandbox Code Playgroud)

你必须考虑:和中$缀运算符的相对优先级.既然$定义为infixr 0,它不会以前那样紧密绑定,:并且您获得以下右关联分组:

    (a b c : d e) $ (f $ g)
Run Code Online (Sandbox Code Playgroud)