我正在编写一个这样的函数:
testing :: [Int] -> [Int] -> [Int]
testing lst1 lst2 =
let t = [ r | (x,y) <- zip lst1 lst2, let r = if y == 0 && x == 2 then 2 else y ]
let t1 = [ w | (u,v) <- zip t (tail t), let w = if (u == 2) && (v == 0) then 2 else v]
head t : t1
第一个让我们做的是:返回一个这样的列表:[2,0,0,0,1,0],从第二个let和下一行,我希望输出如下:[2 ,2,2,2,1,0]。但是,它没有工作,并提供解析错误!!
我做错了什么?
答案 0 :(得分:3)
有两种let
:“let
/ in
”类型,可以出现在表达式可以的任何位置,“let
没有{ {1}}“善良,必须出现在理解或阻止中。由于您的函数定义不在其中,因此in
必须使用let
,例如:
in
或者,由于您可以在每个testing :: [Int] -> [Int] -> [Int]
testing lst1 lst2 =
let t = [ r | (x,y) <- zip lst1 lst2, let r = if y == 0 && x == 2 then 2 else y ] in
let t1 = [ w | (u,v) <- zip t (tail t), let w = if (x == 2) && (y == 0) then 2 else y] in
return (head t : t1)
中定义多个内容,因此您可以考虑:
let
代码还有其他问题,但这应该会让你达到解析的程度,至少。
答案 1 :(得分:0)
通过let-binding形成表达式,通常需要
let bindings
in
expressions
(涉及monad时有例外)。
因此,您的代码可以按如下方式重写(简化r
和w
,这些并非真正必要):
testing :: [Int] -> [Int] -> [Int]
testing lst1 lst2 =
let t = [ if y == 0 && x == 2 then 2 else y | (x,y) <- zip lst1 lst2]
t1 = [ if (v == 0) && (u == 2) then 2 else v | (u,v) <- zip t (tail t)]
in
head t : t1
(注意,我还切换了u
和v
,以便t1和t具有相似的形式。
现在给出了[2,0,0,0,1,0]
之类的列表,您的代码似乎正在尝试替换0 with 2 if the previous element is 2
(来自您的代码模式),因此最终所需的输出为[2,2,2,2,1,0]
。
要实现这一点,仅使用两个列表推导或任何固定数量的理解是不够的。您需要以某种方式递归地应用此过程(一次又一次)。因此,我们可以写出一个步骤(并重复应用),而不是仅仅执行两个步骤。使用t1 = ...
行,一步功能可以是:
testing' lst =
let
t1 = [ if (u == 2) && (v == 0) then 2 else v | (u,v) <- zip lst (tail lst)]
in
head lst : t1
现在这给出了:
*Main> testing' [2,0,0,0,1,0]
[2,2,0,0,1,0]
,正如所料。
剩下的工作是根据需要多次应用testing'
。在这里应用它(length lst)
次就足够了。因此,我们可以先写一个辅助函数,在参数上应用另一个函数n
次,如下所示:
apply_n 0 f x = x
apply_n n f x = f $ apply_n (n - 1) f x
这可以满足您的期望:
*Main> apply_n (length [2,0,0,0,1,0]) testing' [2,0,0,0,1,0]
[2,2,2,2,1,0]
当然,您可以将上述内容包含在以下函数中:
testing'' lst = apply_n (length lst) testing' lst
最后:
*Main> testing'' [2,0,0,0,1,0]
[2,2,2,2,1,0]
注意:这不是填充的唯一方法,请参阅fill2
函数in my answer to another question以获取使用有限状态机实现相同功能的示例。