我经常发现自己必须明确指定return将表达式包装在其中IO/Maybe/Either......但我确信必须有一种更好的方法来使其无点.
例如:
countLines :: FilePath -> IO Int
countLines file = readFile file >>= countLines
where countLines = (\d -> return $ (length . lines) d)
有没有办法实现功能的无点样式countLines?为每一步写lambda >>=是令人厌倦的.
countLines :: FilePath -> IO Int
countLines file = readFile file >>= countLines
where countLines = (\d -> return $ (length . lines) d)
Run Code Online (Sandbox Code Playgroud)
顺便说一句,在where子句中使用函数的相同名称并不是一个好习惯:即使函数不是这样,函数看起来也是递归的.
回到问题,上面的代码意味着
countLines file = readFile file >>= (\d -> return $ (length . lines) d)
Run Code Online (Sandbox Code Playgroud)
意思是
countLines file = readFile file >>= (return . (length . lines))
Run Code Online (Sandbox Code Playgroud)
可以写成
countLines file = length . lines <$> readFile file
-- or
countLines file = fmap (length . lines) $ readFile file
Run Code Online (Sandbox Code Playgroud)
人们可以更进一步,也可以删除这file一点,但可读性会受到轻微伤害.
countLines = fmap (length . lines) . readFile
Run Code Online (Sandbox Code Playgroud)
有没有办法为countLines函数实现无点样式?为>>的每一步写lambda是令人厌倦的.
那么,在一般情况下,无点样式几乎不可读.为什么不使用do notation呢?
countLines :: FilePath -> IO Int
countLines file = do
d <- readFile file
return . length . lines $ d
Run Code Online (Sandbox Code Playgroud)
在这种情况下,这并不像pointfree-ish变体那样优雅,但更为通用.即使链接很多>>=s有时会使用以下样式:
foo =
m1 >>= \x1 ->
m2 >>= \x2 ->
m3 >>= \x3 ->
...
mN >>= \xN ->
return (...)
Run Code Online (Sandbox Code Playgroud)
在这里使你的功能
countLines :: FilePath -> IO Int
countLines file = readFile file >>= countLines
where countLines = (\d -> return $ (length . lines) d)
Run Code Online (Sandbox Code Playgroud)
pointfree,我们需要先将其重构为:
countLines :: FilePath -> IO Int
countLines file = readFile file >>= countLines
where countLines = (\d -> return $ (length . lines) $ d)
Run Code Online (Sandbox Code Playgroud)
现在,我们可以用其他函数组合返回,就像这样(我们可以删除括号):
countLines :: FilePath -> IO Int
countLines file = readFile file >>= countLines
where countLines = (\d -> return . length . lines $ d)
Run Code Online (Sandbox Code Playgroud)
现在我们可以拿出这一点(再次,删除括号):
countLines :: FilePath -> IO Int
countLines file = readFile file >>= countLines
where countLines = return . length . lines
Run Code Online (Sandbox Code Playgroud)
现在可以内联函数:
countLines :: FilePath -> IO Int
countLines file = readFile file >>= return . length . lines
Run Code Online (Sandbox Code Playgroud)
作为一个额外的好处,如果你想让countLines完全无点,你可以使用Kleisi组合运算符(找到Control.Monad)代替bind,如下所示:
countLines :: FilePath -> IO Int
countLines = readFile >=> return . length . lines
Run Code Online (Sandbox Code Playgroud)
虽然可以说其他版本更具可读性.
最后一个也可以写成:
countLines :: FilePath -> IO Int
countLines = return . length . lines <=< readLine
Run Code Online (Sandbox Code Playgroud)
它的优势在于您可以从右到左阅读该功能,并确切了解该功能如何"流动".
| 归档时间: |
|
| 查看次数: |
237 次 |
| 最近记录: |