gpt4 book ai didi

Haskell—— pretty-print 列表的问题

转载 作者:行者123 更新时间:2023-12-02 06:16:49 33 4
gpt4 key购买 nike

我是 Haskell 新手,我通读并消化了 Learn You A Haskell For Great Good ,一路上尝试一些事情。对于我的第一个项目,我想尝试经典:FizzBu​​zz。所以我想出了以下代码:

import System.IO

fizzBuzz :: (Integral a) => a -> String
fizzBuzz num
| fizz && buzz = "FizzBuzz"
| fizz = "Fizz"
| buzz = "Buzz"
| otherwise = show num
where fizz = num `mod` 3 == 0
buzz = num `mod` 5 == 0

main = print $ map fizzBuzz [1..100]

效果很好,只是我得到了一个看起来相当密集的列表,很难阅读。所以我尝试了这个主要功能:

main = map putStrLn $ map fizzBuzz [1..100]

这给了我错误无法将预期类型“IO t”与推断类型“[IO ()]”匹配。我尝试了六种方法,但似乎都没有帮助。做我想做的事情的正确方法是什么?

最佳答案

map :: (a -> b) -> [a] -> [b]
putStrLn :: Show a => a -> IO ()
map putStrLn :: Show a => [a] -> [IO ()]

您有一个列表 IO ()行动。

main :: IO ()

您需要将它们加入到一个 IO () 中行动。

您想要做的就是执行这些 IO () 中的每一个sequence 中的操作/sequence_ :

sequence :: Monad m => [m a] -> m [a]
sequence_ :: Monad m => [m a] -> m ()

为了方便起见,mapM/mapM_将在列表上映射函数并对生成的单子(monad)结果进行排序。

mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()

所以你的固定代码将如下所示:

main = mapM_ putStrLn $ map fizzBuzz [1..100]

虽然我可能会这样写:

main = mapM_ (putStrLn . fizzBuzz) [1..100]

甚至是这样:

main = putStr $ unlines $ map fizzBuzz [1..100]
<小时/>

让我们编写自己的sequence 。我们想要它做什么?

sequence [] = return []
sequence (m:ms) = do
x <- m
xs <- sequence ms
return $ x:xs
  • 如果列表中没有剩余内容,则返回(注入(inject)到 monad 中)一个空结果列表。
  • 否则,在 monad 内,
    • 绑定(bind)(对于 IO monad,这意味着执行)第一个结果。
    • sequence列表的其余部分;绑定(bind)该结果列表。
    • 返回第一个结果的缺点和其他结果的列表。

GHC 的库使用的内容更像 foldr (liftM2 (:)) (return [])但这对新手来说很难解释;现在,请相信我的话,它们是等效的。

sequence_更容易,因为它不需要跟踪结果。 GHC 的库将其实现为 sequence_ ms = foldr (>>) (return ()) ms 。让我们扩展 foldr 的定义:

  sequence [a, b, c, d]
= foldr (>>) (return ()) [a, b, c, d]
= a >> (b >> (c >> (d >> return ())))

换句话说,“执行a,丢弃结果;执行b,丢弃结果,……最后,返回()”。

mapM  f xs = sequence  $ map f xs
mapM_ f xs = sequence_ $ map f xs
<小时/>

另一方面,您甚至不需要了解 monad,使用替代 unlines解决方案。

unlines 是什么意思?做?嗯,lines "a\nb\nc\nd\n" = ["a", "b", "c", "d"] ,所以当然unlines ["a", "b", "c", "d"] = "a\nb\nc\nd\n" .

unlines $ map fizzBuzz [1..100] =unlines ["1", "2", "Fizz", ..] ="1\n2\nFizz\n..."然后它会转到 putStr 。由于 Haskell 的懒惰魔力,完整的字符串永远不需要在内存中构建,因此这将很高兴地转到 [1..1000000]或更高:)

关于Haskell—— pretty-print 列表的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2016488/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com