【问题标题】:Haskell, List as input for a function, How?Haskell,列表作为函数的输入,如何?
【发布时间】:2017-03-30 14:07:01
【问题描述】:

在我的课程作业中,我收到了以下问题;

定义一个函数

flatten :: [(Char,Int)] -> String

将字符和数字对列表展平为字符串。例如:

flatten [('a',5),('b',4),('c',2)]
"a5b4c2"
flatten [('d',9),('d',3)]
"d9d3"

我的问题是,每当我尝试定义此函数时,都会收到与 [(Char, Int)] 输入相关的类型错误。例如;

Couldn't match type '(Char, Int)' with '[Char]'
Expected type: [[Char]]
Actual type: [(Char, Int)]

我已经尝试了更多的方法来编写这个定义,而且我数不清,所以我没有任何特定的代码要显示,也没有任何特定的错误(我不断收到不同的错误……太多了)。到目前为止,我所拥有的是;

flatten :: [(Char, Int)] -> String
flatten [] = []

我想我的下一行应该是这样的;

flatten ???? = concat (????)

但我不知道用什么来代替这些问号,而且 Google 搜索/课堂笔记没有提供可遵循的示例。 有什么想法吗?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    很明显,在列表为空的情况下,它的形式为((ca,cb):cs)ca Charcb Int 和@ 987654327@列表的其余部分[(Char,Int)]

    在这种情况下,我们可以简单地用show :: Show a => a -> String 为该序列ca:(show cb) 构造一个字符串,我们将一个整数转换为其对应的String。接下来我们将列表剩余部分的扁平化连接到该字符串,所以:

    flatten ((ca,cb):cs) = ca:(show cb ++ flatten cs)
    

    或全部:

    flatten :: [(Char, Int)] -> String
    flatten [] = []
    flatten ((ca,cb):cs) = ca:(show cb ++ flatten cs)
    

    【讨论】:

      【解决方案2】:

      首先,我们尝试从(Char, Int) 创建一个String。如果我们能做到这一点,我们几乎已经做到了,因为我们可以为所有(Char, Int) 做到这一点。所以让我们转换一个(Char, Int)

      flattenSingle :: (Char, Int) -> String
      flattenSingle (c, i) = c : show i
      

      现在,我们需要对所有条目都这样做:

      flattenAll :: [(Char, Int)] -> [String]
      flattenAll xs = map flattenSingle xs
      

      最后但同样重要的是,我们需要将concat [String][[Char]])转换为String[Char]):

      flatten :: [(Char, Int)] -> String
      flatten xs = concat (flattenAll xs)
      

      我们完成了。我们是怎么做到的?好吧,我们从一个更简单的问题开始,即如何从 (Char, Int) 中获取单个 String,并使用它来获得我们的结果。

      这是一个函数中的所有内容:

      flatten = concat . map flattenSingle
        where
          flattenSingle (c, i) = c : show i
      

      由于经常使用concat . map f,因此有一个函数,称为concatMap

      flatten :: [(Char, Int)] -> String
      flatten = concatMap flattenSingle
        where
          flattenSingle (c, i) = c : show i
      

      【讨论】:

      • + 对于concatMap 我最初的想法是flatten = concat.map (\(c,i) -> c : show i)
      【解决方案3】:

      让我们想想flatten 中的内容和结果。 flatten,获取类型对列表:(Char, Int) 并生成 [Char];它从现有列表中生成一个列表。这会响铃吗?

      flatten xs = [ c | (char, int) <- xs, c <-[char] ++ show int]
      

      我们可以顺序解构给定列表中的每一对;对于每一对,我们将每个组件转换为一个字符串,以便将它们连接起来。现在我们每对都有一个字符串,我们只需将每个字符取出来生成最终的字符串。

      【讨论】:

        【解决方案4】:
        flatten = mconcat. map (\(c,i) -> [c] ++ show i)
        

        【讨论】:

          【解决方案5】:

          你也可以使用foldl来表达你的意图:

          a=[('a',5),('b',4),('c',2)]
          f b (x,y)=b++[x]++(show y)   
          result=foldl f "" a
          

          或者您可以将其设为单线:

          解决方案 1:

          foldl (\b (x,y)->b++[x]++(show y)) "" a
          

          解决方案 2:

          concat $ map (\(x,y)->[x]++show y) a
          

          解决方案 3:(与解决方案 1 相比效率更高)

          foldr (\(x,y) b->b++[x]++(show y)) "" a
          

          【讨论】:

          • foldr 在这里是可以接受的(尽管 concatMap 更好,如其他地方所述)。然而, foldl 是一个糟糕的选择。以这种方式使用是相当昂贵的。
          • 感谢您的提示。
          猜你喜欢
          • 2020-03-09
          • 1970-01-01
          • 2020-03-19
          • 2022-11-15
          • 1970-01-01
          • 1970-01-01
          • 2018-07-25
          • 1970-01-01
          • 2015-01-05
          相关资源
          最近更新 更多