我正在尝试在String
列表中添加String
的某些字母。
例如:"Haskell" -> ['a', 's']
(仅a
和s
)
运行后,我收到错误消息“范围内注意:xs
”。所以它没有列表(我认为)。将列表转换为新列表(例如mirrorList)没有问题,但是在获得字符串输入后如何“创建”列表?
letterList :: String -> [String]
letterList s = let x = head s in
if x == 'a' || x == 's' then x:xs
else letterList (tail x)
答案 0 :(得分:6)
在找到准确的问题之前,让我们修复这些类型。您的示例"Haskell" -> ['a', 's']
表示此函数的类型为String -> String
,而不是String -> [String]
。请注意,String
只是[Char]
的类型别名。
错误消息表示您有一个引用值xs
的表达式,但您没有定义任何名为xs
的内容。我怀疑你选择x:xs
是模式匹配。该模式位于=
的左侧,并声明了您可以在右侧引用的x
和xs
。而且由于空列表无法解析为头尾,因此需要一个单独的案例。
我猜测你看到的结果如下:
letterList :: String -> String
letterList [] = []
letterList (x:xs) = if x == 'a' || x == 's' then x:rest else rest
where rest = letterList xs
我认为你在这里使用递归只是为了练习,但是为了它的价值,我建议把它写成
letterList :: String -> String
letterList = filter (`elem` "as")
答案 1 :(得分:2)
不在范围内:
xs
这就是它所说的内容:没有找到名为xs
的变量,但你试图使用它。当你尝试调用一个无法定义的方法时,你也会在Java中遇到同样的错误。
将列表转换为新列表(例如mirrorList)没有问题
这是你在Haskell中永远不需要†的东西。如果您有一个列表,您可以随时使用它,无论您喜欢哪种方式。由于引用透明性,它的值和副本之间永远不会有差异。而且我不确定你在这里“转换”是什么意思,但通常可以避免在Haskell中转换任何内容:参数多态通常允许你从一开始就生成正确的类型。
现在关于“我如何创建列表” - 你已经做到了! :
中的cons(prepend)运算符x:xs
构造了一个新列表。 ......当然,它基于现有的列表xs
。这实际上是生成新列表的唯一方式,因为列表构造函数总是需要一个尾部来预先添加元素。如果您不想/不需要/有任何此类列表,请使用始终可用的空的,[]
。
† 即使在Haskell中,您有时也需要使用可变数据(通常是ST
monad中的数组 - 内部可变,但从外部查看时仍保证引用转发)。在这样的计算中,可能需要复制一个数组,就像它可以用过程语言一样。
答案 2 :(得分:1)
错误消息显示 - 您在右侧使用xs
但在使用之前未定义它(即之前没有let
语句,之后没有where
语句,并且也不在左手边。
您还有一个问题是您基本上是在实施过滤器,但结果类型是String
而不是[String]
!
letterList :: String -> [String]
letterList [] = []
letterList (x:xs) = if x == 'a' || x == 's'
then [x]: letterList xs
else letterList xs
String
!String
和head = x
中的tail = xs
,这更加可读和正确(tail x
错误,您尝试结束单个字母!)[x]
会转换Char
中的单个字母String = [Char]
。letterList str = [[x] | x <- str, x `elem` "as"]
这被称为列表理解,这将是我将给你思考的下一个“作业”。
或
letterList str = map (\x -> [x]) $ filter (`elem` "as") str
使用高阶函数(filter
和map
),这是我给你的第二个任务。
当然,您也可以将类型签名更改为String -> String
,如@ChrisMartin所示 - 然后您可以省略[
语句中的]
,[x]
和省略map (\x -> [x])
事。
答案 3 :(得分:-3)
似乎是一个复制粘贴错误:尝试用(尾部x)替换xs ...然后考虑一下情感列表问题......也许你会替换左侧的那一面;-)