【问题标题】:Haskell iterate over a listHaskell 遍历列表
【发布时间】:2011-11-25 17:15:33
【问题描述】:

我知道您在 Haskell 中的想法会有所不同,但有人可以快速回答我如何遍历列表或嵌套列表并根据列表元素的值打印出一个字符。

list1 = [[1 0 0][0 1 0][0 0 1]]

通过遍历这个嵌套列表,它应该打印出 x 代表 0 和 y 代表 1

yxx
xyx
xxy

谢谢

【问题讨论】:

  • 更一般地说,当从命令式语言迁移到函数式语言时,您可能不想再考虑“迭代列表”,而更多地考虑像 mapfilter 这样的函数.

标签: list haskell nested loops


【解决方案1】:

首先,我认为你的意思是:

list1 :: [[Int]]
list1 = [[1,0,0],[0,1,0],[0,0,1]]

至于你想要什么:

valueOf :: Int -> Char
valueOf 0 = 'x'
valueOf 1 = 'y'
valueOf _ = 'z'

listValues :: [[Int]] -> [String]
listValues = map (map valueOf)

printValues :: [[Int]] -> IO ()
printValues = putStrLn . unlines . listValues

然后在 ghci 中:

*Main> printValues list1 
yxx
xyx
xxy

【讨论】:

    【解决方案2】:

    用类似的东西定义 f

    f x = if x == 0 then 'x' else 'y'
    

    然后

    map (map f) [[1,0,0],[0,1,0],[0,0,1]]
    

    是你想要的,或者如果你想要它更漂亮:

    map' = map.map
    map' f [[1,0,0],[0,1,0],[0,0,1]]
    

    【讨论】:

      【解决方案3】:

      试试这个:

      fun :: [[Int]] -> [String]
      fun = (map . map) (\x -> if x == 0 then 'x' else 'y')
      

      如果您确实需要打印结果:

      printSomeFancyList :: [[Int]] -> IO ()
      printSomeFancyList = putStrLn . unlines . fun
      

      【讨论】:

        【解决方案4】:

        如果你对任意嵌套列表感兴趣,那么你可以这样写(任意嵌套列表本质上是一棵树):

        data Nested a = Leaf a | Nest [Nested a] deriving Show
        
        traverse :: Nested Integer -> Nested Char
        traverse (Leaf x) = Leaf (valueOf x)
        traverse (Nest xs) = Nest (map traverse xs)
        
        valueOf :: Integer -> Char
        valueOf 0 = 'x'
        valueOf 1 = 'y'
        valueOf _ = 'z'
        

        你可以这样做:

        Main> let nl = Nest [Leaf 1, Leaf 0, Nest [Leaf 0, Leaf 0, Leaf 1, Nest [Leaf 1, Leaf 1, Leaf 0]], Nest [Leaf 1, Leaf 1]]
        Main> traverse nl
        Nest [Leaf 'y',Leaf 'x',Nest [Leaf 'x',Leaf 'x',Leaf 'y',Nest [Leaf 'y',Leaf 'y',Leaf 'x']],Nest [Leaf 'y',Leaf 'y']]
        

        函数traverse接受Integers的任意嵌套列表,并根据valueOf规则返回对应的Chars嵌套列表

        【讨论】:

        • 尝试定义一个真正的任意嵌套列表可能会很有趣:即类型的总和 [a], [[a]], [[[a]]], [[[[a]]]], ... 不允许例如。 [[0,1],2,[[3],4]],这是一棵树允许的。
        【解决方案5】:
        iterateList = foldl1 (>>).concat.intersperse [putStrLn ""].(map.map) (\c ->  putStr $ if (c==0) then "X" else "Y")
        

        【讨论】:

        • 你需要导入 Data.List (intersperse,foldl1)
        • 您可以将concat.intersperse 替换为intercalate,并应将foldl1 (>>) 替换为foldr (>>) (return ()),这样它就不会崩溃。 sequence_ 更好。
        • 此外,您可以使用mapM_ 将其带到mapM_.((>> putStrLn "").).mapM_ $ \c -> ...。 :)
        【解决方案6】:

        使用map 的解决方案是首选的 Haskell 样式。但是在你学习的时候,你可能会发现显式递归更容易理解。像这样:

        charSub :: Int -> Char
        charSub 0 = 'x'
        charSub 1 = 'y'
        charSub x = error "Non-binary value!"
        
        listSub :: [Int] -> String
        listSub [] = []
        listSub (x:xs) = (charSub x) : (listSub xs)
        
        nestedSub :: [[Int]] -> String
        nestedSub [] = []
        nestedSub (y:ys) = (listSub y) ++ "\n" ++ (nestedSub ys) 
        

        map 做了几乎相同的事情——它将一个函数应用于列表中的每个元素。但可能更容易看到这里发生了什么。

        【讨论】:

          【解决方案7】:

          解决方案

          cambiar = putStr.unlines.(map (map f)) where f x = if x == 0 then 'x' else 'y'
          

          【讨论】:

          • cambiar [[1,0,0],[1,1,0],[1,1,1]] ==> yxx yyx yyy
          猜你喜欢
          • 1970-01-01
          • 2018-09-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-17
          • 1970-01-01
          • 2022-10-12
          • 1970-01-01
          相关资源
          最近更新 更多