我应该拆分一个字符串并返回在传递的字符之前发生的子字符串,但我们只是启动Haskell,对我来说就像中文一样。我一直搞乱它,但没有运气。 这是我到目前为止所做的:
--spanString returns substring of string s before char c
spanString (c, [s])::(c, [s]) -> []
spanString (c, a:b) =
let (x, y) = spanString (c, b)
in
if a < c then (a:x,y)
else (x, a:y)
我搞砸了什么?
答案 0 :(得分:4)
首先,你的类型签名完全搞砸了。它必须不存在或者是spanString :: <some type>
形式。即使我们忽略了双冒号之前的(c, [s])
,其余的仍然是奇怪的。可以将其视为“将(c, [s])
类型的值赋予任何c和s的类型[]
的值的函数”(c和s是类型变量)。首先,Haskell中没有类型[]
。没有元素类型的列表类型。接下来,我们无法使用任何c
和s
。我们必须能够比较它们,对吗?
实际上,让我们暂时避免使用多态,并准确指定我们想要的类型。我们想要一个字符和一个字符列表,由于某种原因打包成元组:(Char, [Char])
。请注意,Char
以大写字母开头,这意味着它不是类型变量,而是具体类型。我们的结果类型怎么样?如果您信任问题描述,则需要返回一个字符列表([Char]
),但是如果查看代码,它显然会返回列表元组(([Char], [Char])
)。好吧,也许第二个列表很有用,让我们暂时离开:
spanString :: (Char, [Char]) -> ([Char], [Char])`
现在您的代码已编译。
但是,在运行时,它会崩溃,但例外情况为Non-exhaustive patterns in function spanString
。这是因为当传递的列表为空时,您不处理这种情况。如果你这样做,可以添加像
spanString (_, []) = ([], [])
,你的功能运行良好,但现在让我们来看看它的作用。事实证明,你有一个列表分区功能:它返回给定字符串的所有字符,小于c
作为元组的第一个元素,所有其他字符作为第二个元素。对我来说似乎是一个错误(你实现了一个完全不同的功能!)。
答案 1 :(得分:3)
呃,非常多。
首先,您的类型声明是错误的。 Haskell对类型使用大写名称,并且它不像大多数语言那样传递括号中的参数。我们写了
y = sin x
而不是
y = sin (x)
你可能想要像
这样的东西spanString :: Char -> String -> String
你对spanString的定义在语法上是正确的,但仍然是错误的。这样考虑一下:如果第一个字符不匹配,那么你想要spanString其余的字符串然后返回结果,前面加上第一个字符。如果第一个字符匹配,那么您想要返回“”。
答案 2 :(得分:2)
您的类型定义错误。
spanString :: Char-> String-> String
spanString _ [] = []
spanString c (x:xs) | c==x = []
| otherwise = x:spanString c xs
答案 3 :(得分:0)
仅供参考,像这样的实用程序函数几乎总是可以在Prelude或标准库中找到。在这种情况下,takeWhile
会有所帮助:
spanString :: (Char, String) -> String
spanString (c, s) = takeWhile (/= c) s
(即,在不等于c
时)继续拍摄角色。
在元组中传递参数有点奇怪,但如果这就是所需要的那么就是它。