使用功能组合的fmap的惯用法

Chr*_*ner 0 haskell

我对Haskell很新,但我很喜欢学习它,它与我以前用过的所有东西都有所不同.我在Monads上读了一两本书以及它们如何影响流量,但是我仍然有点麻烦.为了更好,我正在努力解决代码问题的优秀问题,现在我遇到问题2,我已经在下面发布了我的代码,它运行正常,但感觉不尽如人意.

具体来说,我想知道如何清理这个:

main = getContents >>= (return . sum . (fmap getSquareFootage) . lines) >>= print

我不喜欢混合函数组合和fmap AND这样>>=的行,我觉得很难读.是否有更惯用的方法来实现相同的结果?我也对任何和所有Haskell风格的建议持开放态度,我真的没有人可以谈论这个,谢谢!

TLDR; 我怎么能惯用地组合fmap,.>>=

import Data.List.Split (splitOn)

main :: IO ()
main = getContents >>= (return . sum . (fmap getSquareFootage) . lines) >>= print

getSquareFootage :: String -> Int
getSquareFootage box = area dims + slack dims
    where dims =  read <$> splitOn "x" box
        slack = minimum . sides
        sides [l, w, h] = [l*w, w*h, h*l]
        area [l, w, h] = 2*l*w + 2*w*h + 2*h*l
Run Code Online (Sandbox Code Playgroud)

lef*_*out 5

如果你在returnKleisli箭头的最后使用只是为了将结果提供给另一个,你可以将它作为一个纯函数预先组合:return . f >>= q相当于q . fmonad定律.

main = getContents >>= print . sum . (fmap getSquareFootage) . lines
Run Code Online (Sandbox Code Playgroud)

我已经习惯了它的固定性.高于infixl 1 >>=.说到固定性:你永远不需要用parens包围函数调用,如果它们已经被中缀包围了!而且由于你的专业列表,你可以使用map而不是fmap(虽然这是一个品味的问题).

main = getContents >>= print . sum . map getSquareFootage . lines
Run Code Online (Sandbox Code Playgroud)

尽管可能有人认为订单令人困惑,但IMO并不算太糟糕.你可以从右到左,

main = print . sum . map getSquareFootage . lines =<< getContents
Run Code Online (Sandbox Code Playgroud)

或者如果你愿意,从左到右

import Control.Arrow

main = getContents >>= (lines >>> map getSquareFootage >>> sum >>> print)
Run Code Online (Sandbox Code Playgroud)