好的,所以我来自python背景,是haskell的新手,正在做作业。我已经解决了问题本身,但是我的逻辑/代码看起来很丑陋,想知道改进它的方法。我想做的是遍历一个列表,并以该列表作为参数来调用另一个函数。
假设我想在haskell中实现以下目标。
EXTRA_STREAM
所以我想离开input = [1,2,2,3,3,4,5]
output = [1,4,5] #occurs Once
通常我会怎么做
x->y
我该如何在haskell中进行迭代?我有一个功能可以很好地发生的事件,它需要一个值并列出并返回布尔值,就像python一样。
def checksOnce(input):
lst = []
for val in input:
if occursOnce(val,input):
lst.append(val)
print(lst)
和类似checksOnce :: [Int] -> [Int] -> [Int]
checksOnce [] lst = []
checksOnce (x:xs) lst
| occursOnce x lst = [x] ++ checksOnce xs lst
| otherwise = checksOnce xs lst
之类的东西来调用上述函数。
上面的方法效果很好,就我的硬件而言已经足够了,但是传递相同的参数Once是多余的!我如何从mainFunc lst = checksOnce lst lst
到checksOnce :: [Int] -> [Int] -> [Int]
,并像上面的python代码一样仅使用一个列表进行迭代,而不是将同一列表一次传递给函数?
谢谢
答案 0 :(得分:6)
Haskell具有列表理解功能,因此您可以这样做:
\f xs -> [x | x <- xs, f x xs]
您也可以使用过滤器执行此操作:
\f xs -> filter (\x -> f x xs) xs
答案 1 :(得分:3)
在Haskell中编写此功能的最简单,可能也是最惯用的方法是使用filter
:
checksTwice :: (Eq a) => [a] -> [a] -- you can keep it as [Int] -> [Int] if you like, but this more general type signature is better because the function works on any type that can be compared for equality
checksTwice xs = filter (\x -> occursTwice x xs) xs
或者,如果您愿意(尽管收益值得商)),则以“无点”样式重写lambda:
checksTwice :: (Eq a) => [a] -> [a]
checksTwice xs = filter (flip occursTwice xs) xs
(这正是@ user2407038的注释中建议的答案-道歉“窃取”您的答案)
答案 2 :(得分:2)
就像在Python中一样,您希望变量lst
仅对函数checksTwice
可见,而对参数不可见。 Haskell使某些人陷入循环,而缺少循环原语-解决方案通常是高阶函数的辅助函数。
checksOnce :: [Int] -> [Int]
checksOnce xs = go xs xs
where go [] _ = []
go (x:xs) lst
| occursOnce x lst = x : go xs lst
| otherwise = go xs lst
但是这种模式,包括x
,当且仅当f x
只是一个过滤器,所以...
checksOnce x = filter (`occursOnce` lst) xs
正如@RobinZigmond所指出的,相对于您想要的行为,这仍然存在一个错误。