如何将数字列表转换为字符串而不格式化

时间:2019-06-28 17:36:23

标签: haskell haskell-platform

这是我到目前为止所拥有的:

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”的列表。

2 个答案:

答案 0 :(得分:4)

了解问题

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 xString
  • toStr xsString
  • 函数:需要String[String]

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

了解下一个问题*

现在您应该还有其他一些问题。首先,您尝试使用Num a => a的{​​{1}}。函数show不是show的一部分,而是Num类的一部分,因此请将Show更改为Num a =>

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

Show a =>

toStr (x:xs) | length xs == 0 = [] 之后不加空格,此代码将忽略最后一个值x,并返回空列表。它不处理没有“最后一个元素”而您只有空列表的情况。要尝试使用x

放在一起

toStr [] = []

结果为:

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

惯用代码

上面的结果很好,但是编写Haskell时通常不需要手动的原始递归函数。大多数操作是数据上的> toStr [1,0,0,1,1] "10011" map类型。在这种情况下,它是fold函数的映射(注意如何show处理每个元素)和show函数的fold的映射-也称为字符串连接

++

即使这可以进一步简化。非常普遍,存在一个特殊功能toStr2 xs = foldr (++) "" (map show xs) -- > toStr2 [1,0,0,1,1] -- "10011"

concatMap

我们可以“ eta reduce”(删除函数定义/应用程序的最外层参数-考虑将函数定义为另一个函数而不是其产生的值):

toStr3 xs = concatMap show xs

或者,我们可以重新获得fold和map的原始动词年龄。 toStr4 = concatMap show 函数只是在列表上工作的concatMap + fold的特定类型。有一个更通用的map可以与任何产生monoid的函数一起使用(列表就是这样的结构,这意味着String也是如此,因为它们是字符列表):

foldMap

答案 1 :(得分:1)

如Sergey所述,不能使用':'运算符,因为表达式“ show x”返回的字符串不是单个字符。

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

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 函数。如果这样做,事情可能会变得非常丑陋,因为我们潜在的无限懒惰列表。