规范并不完全清楚,但听起来你想收集输入中'Z'之后三个位置出现的所有字符,以便从
"BUZZARD BAZOOKA ZOOM"
我们得到
"RDKM"
如果没有对问题进行更清晰的表述,就很难给出准确的建议。但我希望我能帮助你克服一些小烦恼,这样你就可以接触到问题的实际逻辑。
让我们从类型开始。你有
someFun :: String => String -> String -> String
但=> 的左侧是类型表达式的属性 的位置,通常涉及可以代表许多类型的变量,例如Eq a(意味着无论a 是什么类型,我们可以测试相等性)。 String 是一个类型,而不是一个属性,所以它不能站在=> 的左边。算了吧。这给了
someFun :: String -- input
-> String -- accumulating the output (?)
-> String -- output
尚不清楚您是否真的需要蓄能器。假设你知道
"ZARD BAZOOKA BOOM" -- "DKM", right?
你能计算输出吗
"ZZARD BAZOOKA BOOM" -- "RDKM"
?只是在前面多了一个'R',对吧?您正在使用尾递归来做下一件事,而通常更容易考虑应该做什么。如果您知道列表尾部的输出是,那么请说出整个列表的输出是。为什么不直接将输入映射到输出,所以
someFun :: String -> String
现在,模式匹配,从最简单的模式开始
someFun s = undefined
你能看到足够的输入来确定输出吗?显然不是。输入是空的还是有第一个字符很重要。分为两种情况。
someFun "" = undefined
someFun (c : s) = undefined -- c is the first Char, s is the rest of the String
第一个字符是否为'Z' 也很重要。注意Char 使用单 引号,String 使用双 引号:它们是不同的类型。
someFun "" = undefined
someFun ('Z' : s) = undefined -- the first Char is Z
someFun (c : s) = undefined
在'Z' 的情况下,您还想确保s 至少有三个字符,我们关心第三个字符,所以
someFun "" = undefined -- input empty
someFun ('Z' : s@(_ : _ : d : _)) = undefined -- first is 'Z' and d is 3 later
someFun (c : s) = undefined -- input nonempty
@ 是一个“as 模式”,允许我将整个尾部命名为 s 并检查它是否匹配 (_ : _ : d : _),抓住 'Z' 之后的第三个字符。
到目前为止,我没有考虑输出,只是我需要查看输入。让我们弄清楚输出必须是什么。在第一种情况下,空输入给出空输出
someFun "" = ""
someFun ('Z' : s@(_ : _ : d : _)) = undefined -- first is 'Z' and d is 3 later
someFun (c : s) = undefined -- input nonempty
在其他两种情况下,我们可以假设someFun s 已经告诉我们列表尾部的输出,所以我们只需要弄清楚如何完成整个列表的输出。在最后一行中,尾部的输出正是我们想要的。
someFun "" = ""
someFun ('Z' : s@(_ : _ : d : _)) = undefined -- first is 'Z' and d is 3 later
someFun (c : s) = someFun s
但如果我们发现d 位于初始'Z' 之后的三个位置,我们需要确保d 位于输出的开头。
someFun "" = ""
someFun ('Z' : s@(_ : _ : d : _)) = d : someFun s
someFun (c : s) = someFun s
只是检查:
*Main> someFun "BUZZARD BAZOOKA ZOOM"
"RDKM"
关键的想法是弄清楚如何根据各个部分的输出来表达整个输入的输出:它是什么,而不是要做什么 .在这里,您可以假设尾部的输出 s 已正确计算,因此您只需要确定是否有任何额外的东西要返回。