简体   繁体   English

Haskell,将List作为函数的输入,如何?

[英]Haskell, List as input for a function, How?

I've been given the following question in my coursework; 在我的课程中,我曾被问到以下问题;

Define a function 定义功能

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

that flattens a list of pairs of characters and digits to a string. 将字符和数字对的列表展平为字符串。 For example: 例如:

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

My problem is that whenever I attempt to define this function i get a type error relating the the [(Char, Int)] input. 我的问题是,每当我尝试定义此函数时,我都会得到与[(Char, Int)]输入有关的类型错误。 For example; 例如;

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

I've tried more ways of writing this definition in more ways than I can count, so I don't have any particular code to show, or any particular error ( I kept getting different ones...so many). 我尝试了更多的方式来编写此定义,而不用数数,因此我没有要显示的任何特定代码或任何特定的错误(我不断得到不同的代码...太多了)。 All i have so far is; 到目前为止,我所拥有的只是;

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

i figure my next line should go something like; 我认为我的下一行应该是这样的;

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

but I have no idea what to put in place of these question marks and Google search/class notes give no examples to follow. 但我不知道该用什么代替这些问号,并且Google搜索/课程注释中没有提供任何示例。 any ideas? 有任何想法吗?

Well it is clear that in the case the list is not empty, it is of the form ((ca,cb):cs) with ca the Char , cb the Int and cs the remainder of the list [(Char,Int)] . 很显然,在列表不为空的情况下,其形式为((ca,cb):cs)其中caCharcbIntcs列表的其余部分[(Char,Int)]

In that case we can simply construct a string for that sequence ca:(show cb) with show :: Show a => a -> String we convert an integer to its String counterpart. 在那种情况下,我们可以简单地为带有show :: Show a => a -> String ca:(show cb) show :: Show a => a -> String序列ca:(show cb)构造一个字符串,我们将整数转换为其对应的String Next we concatenate the flattening of remainder of the list to that string, so: 接下来,我们将列表的其余部分的拼合连接到该字符串,因此:

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

Or in full: 或全部:

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

First of all, we try to create a String from a (Char, Int) . 首先,我们尝试从(Char, Int)创建一个String If we can do that we've almost done, since we can do that for all (Char, Int) . 如果我们能够做到这一点,我们几乎就已经做到了,因为我们可以做到所有(Char, Int) So let's transform a single (Char, Int) : 因此,让我们变换一个(Char, Int)

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

Now, we need to do that for all entries: 现在,我们需要对所有条目执行此操作:

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

And last, but not least, we need to concat the [String] (which is a [[Char]] ) to a String (which is a [Char] ): 而在去年,但并非最不重要,我们需要concat[String] (这是一个[[Char]] )的String (这是一个[Char] ):

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

And we're done. 我们完成了。 How did we do that? 我们是如何做到的? Well, we've started with a much easier problem, namely how to get a single String from a (Char, Int) , and used that to get our result. 好吧,我们从一个更简单的问题开始,即如何从(Char, Int)获得单个String ,并以此来获得结果。

Here's everything in a single function: 这是单个函数中的所有内容:

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

Since concat . map f concat . map f以来concat . map f concat . map f is often used, there's a function for that, called concatMap : concat . map f是经常使用的,有一个函数叫做concatMap

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

Let's think about what goes into flatten and what comes out of it. 让我们考虑一下flattenflatten的结果。 flatten , takes a list of pairs of type: (Char, Int) and produces a [Char] ; flatten ,获取类型对的列表: (Char, Int)并产生[Char] it produces a list from an existing list. 它从现有列表中生成一个列表。 Does this ring a bell? 这会响吗?

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

We can sequentially deconstruct each pair in the given list; 我们可以顺序地解构给定列表中的每一对。 for each pair, we turn each component into a string so we can concatenate them. 对于每一对,我们将每个组件转换为字符串,以便可以将它们连接起来。 Now we have a string for each pair, we just need to take each character out to produce the final string. 现在,每对都有一个字符串,我们只需要取出每个字符即可生成最终的字符串。

You might also use foldl to make your intention very clear: 您还可以使用foldl来使意图非常清楚:

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

Or you can make it a one-liner: 或者您可以将其设置为单线:

Solution 1: 解决方案1:

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

Solution 2: 解决方案2:

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

Solution 3: (Being more efficient compared to solution 1) 解决方案3 :(与解决方案1相比效率更高)

foldr (\(x,y) b->b++[x]++(show y)) "" a
flatten = mconcat. map (\(c,i) -> [c] ++ show i)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM