3

下一行应该显示它必须如何工作..

[14,2,344,41,5,666][(14,2),(2,1),(344,3),(5,1),(666,3)]

["Zoo","School","Net"][("Zoo",3),("School",6),("Net",3)]

到目前为止,这就是我的代码

zipWithLength :: [a] -> [(a, Int)]
zipWithLength (x:xs) = zipWith (\acc x -> (x, length x):acc) [] xs

我想弄清楚第二行的问题是什么。

4

4 回答 4

2

如果将数字转换为字符串(使用show),则可以length对其应用:

Prelude> let zipWithLength = map (\x -> (x, length (show x)))
Prelude> zipWithLength [14,2,344,41,5,666]
[(14,2),(2,1),(344,3),(41,2),(5,1),(666,3)]

但是,您不能对字符串列表使用相同的函数:

Prelude> zipWithLength ["Zoo","School","Net"]
[("Zoo",5),("School",8),("Net",5)]

这些数字不是字符串的长度,而是它们的表示:

Prelude> show "Zoo"
"\"Zoo\""
Prelude> length (show "Zoo")
5

如评论中所述,其他类型的元素可能会出现类似问题:

Prelude> zipWithLength [(1.0,3),(2.5,3)]
[((1.0,3),7),((2.5,3),7)]
Prelude> show (1.0,3)
"(1.0,3)"
Prelude> length (show (1.0,3))
7
于 2018-03-23T13:14:36.290 回答
2

如果你想对列表的每个元素应用一个函数,那就是map :: (a -> b) -> [a] -> [b]. 因此,该映射采用一个函数f和一个列表xs,并生成一个列表ys,使得 的第i个元素应用于 的第ysi元素。fxs

所以现在唯一的问题是我们想要什么映射函数。我们想要获取一个元素x,并返回一个 2-tuple (x, length x),我们可以用lambda 表达式来表达:

mapwithlength = map (\x -> (x, length x))

或者我们可以使用ap :: Monad m => m (a -> b) -> m a -> m b

import Control.Monad(ap)

mapwithlength = map (ap (,) length)

一个问题是这对 s 不起作用Int,因为它们没有length. 我们可以show在这里使用,但是有一个额外的问题:如果我们show在 a 上执行String,我们会得到一个字符串文字(这意味着我们会得到一个带引号的字符串,并且其中一些字符被转义了)。基于这个问题,我们不希望这样。

我们可以为它定义一个参数化函数,例如:

mapwithlength f = map (ap (,) (length . f))

我们基本上可以把它留给用户。如果他们想使用整数,他们必须调用它:

forintegers = mapwithlength show

对于Strings:

forstrings = mapwithlength id
于 2018-03-23T13:29:35.397 回答
1

安装number-length软件包后,您可以执行以下操作:

module Test where
import           Data.NumberLength

-- use e.g for list of String
withLength :: [[a]] -> [([a], Int)]
withLength = map (\x -> (x, length x))

-- use e.g for list of Int
withLength' :: NumberLength a => [a] -> [(a, Int)]
withLength' = map (\x -> (x, numberLength x))

例子:

>>> withLength ["Zoo", "bear"]
[("Zoo",3),("bear",4)]
>>> withLength' [14, 344]
[(14,2),(344,3)]
于 2018-03-23T13:31:51.760 回答
1

正如 bli 指出的那样,使用计算数字的长度length (show n)不会转移到计算字符串的长度,因为show "foo"变成"\"foo\"". 由于某些东西的长度并不明显,因此您可以使用长度函数参数化 zip 函数:

zipWithLength :: (a -> Int) -> [a] -> [(a, Int)]
zipWithLength len = map (\x -> (x, len x))

使用示例:

> zipWithLength (length . show) [7,13,666]
[(7,1),(13,2),(666,3)]

> zipWithLength length ["Zoo", "School", "Bear"]
[("Zoo",3),("School",6),("Bear",4)]

> zipWithLength (length . concat) [[[1,2],[3],[4,5,6,7]], [[],[],[6],[6,6]]]
[([[1,2],[3,4],[5,6,7]],7),([[],[],[6],[6,6]],3)]
于 2018-03-23T13:44:54.880 回答