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

时间:2016-05-07 19:34:56

标签: haskell

我对Haskell很陌生,但我喜欢学习它,它与我以前用过的所有东西都有所不同。我已经在Monads上读了一两本书,以及它们如何影响流量,但我仍然有点麻烦。为了让我更好地完成优秀的代码问题,现在我在problem 2,我已经在下面发布了我的代码并且它正常运行,但是没有#39;感觉尽可能干净。

特别是我想知道如何清理它:

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

2 个答案:

答案 0 :(得分:5)

如果您在Kleisli箭头末尾使用return仅将结果提供给另一个,您可以将其预分解为纯函数:return . f >>= q等效于{{1根据monad法则。

q . f

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

fmap

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

main = getContents >>= print . sum . map getSquareFootage . lines

或从左到右,如果您愿意

main = print . sum . map getSquareFootage . lines =<< getContents

答案 1 :(得分:2)

好吧,我会把它放到一个do块中:

main = do
    ls <- lines <$> getContents
    let s = sum $ map getSquareFootage ls
    print s