这是我到目前为止所拥有的:
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”的列表。
答案 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 x
是String
toStr xs
是String
:
需要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 函数。如果这样做,事情可能会变得非常丑陋,因为我们潜在的无限懒惰列表。