如何在不格式化的情况下将数字列表转换为字符串

How to convert list of numbers to string without formatting

这是我目前拥有的:

toStr :: (Num a) => [a] -> String
toStr (x:xs)
    | length xs == 0 = []
    | length xs > 0 = show x : toStr xs

我一直收到这个错误:

* Couldn't match type `Char' with `[Char]'
  Expected type: [String]
    Actual type: String

我不明白为什么它接收的是 Char 而不是 [Char]。提前致谢。

求助,我想做的是将二进制列表 [1, 0, 0, 1, 1, 0] 转换为这样的列表“100110”。

如 Sergey 所述,不能使用“:”运算符,因为表达式 "show x" returns 是一个字符串而不是单个字符。

下面这段代码似乎可以满足您的要求:

toStr :: (Num a, Show a) => [a] -> String
toStr (x:xs)
    | null xs         = show x  -- avoid using length because of cost
    | not (null xs)   = (show x) ++ (toStr xs)
toStr [] = ""


main = do
    let ls1 = [ 13, 17, 19, 23 ]
    let st1 = toStr ls1
    let st2 = concatMap show ls1 -- as per melpomene's remark
    putStrLn $ "st1 = " ++ st1
    putStrLn $ "st2 = " ++ st2

附带说明一下,Haskell 程序员通常在只想知道列表是否为空时避免使用 length 函数。如果你这样做,事情会变得非常糟糕,因为我们可能有无限的惰性列表。

理解问题

toStr :: (Num a) => [a] -> String
toStr (x:xs)
    | length xs == 0 = []
    | length xs > 0 = show x          :  toStr xs
                       ^              ^      ^
                    This is a String  |      |
                                      |  This is a String
                                   This is a function of type String -> [String] -> [String]

所以你有:

  • show x 这是一个 String
  • toStr xs 这是一个 String
  • 需要 String[String] 的函数 :

关于 toStr xs 的分歧是一个字符串,但 : 预期它是一个字符串列表,这是问题的症结所在。您想将字符串连接成一个字符串 (show x ++ toStr xs)。

了解下一个问题*

现在您应该还有其他一些问题。首先,您有一个 Num a => a,您尝试 show。函数 show 不是 Num 的一部分,而是 Show class 的一部分,因此将 Num a => 更改为 Show a =>

最后,这段代码不能很好地处理空列表的情况:

 toStr (x:xs)
    | length xs == 0 = []

注意到 x 之后没有任何内容,此代码将忽略最后一个值 x 和 return 空列表。它不处理没有 "last element" 并且您所拥有的只是空列表的情况。要处理这个问题,请尝试 toStr [] = [].

放在一起

toStr :: (Show a) => [a] -> String
toStr [] = []
toStr (x:xs) = show x ++ toStr xs

结果为:

> toStr [1,0,0,1,1]
"10011"

惯用代码

以上是一个很好的结果,但是在编写 Haskell 时通常不需要手动原始递归函数。大多数操作都是对数据的 mapfold 类型。在这种情况下,它是 show 函数的映射(注意它是如何 showing 每个元素的)和 ++ 函数的 fold - 也称为字符串连接.

toStr2 xs = foldr (++) "" (map show xs)
-- > toStr2 [1,0,0,1,1]
-- "10011"

即使这样也可以进一步简化。如此普遍,存在一个特殊的功能 concatMap:

toStr3 xs = concatMap show xs

我们可以"eta reduce"(删除函数的最外层参数definition/application - 考虑将一个函数定义为另一个函数而不是它产生的值):

toStr4 = concatMap show

或者,我们可以 re-gain fold 和 map 的原始 verb-age。 concatMap 函数只是 fold + map 的一种特定类型,适用于列表。有一个更通用的 foldMap 适用于任何产生幺半群的函数(列表就是这样一种结构,这意味着字符串也是,因为它们是字符列表):

toStr5 = foldMap show