我正在尝试编写一个我可以用作的函数iterator
iterator l f
,其中l
是Int
个数字的列表,f
是单参数函数。 iterator
函数应该检查当f
函数应用于列表的第一个元素时它= =列表的第二个元素,依此类推所有元素。如果每个元素在应用f
之后等于前一个元素,它应该返回true。
它应该像这样工作:
iterator [3,4,5] (+1) -> True
iterator [2,4,5] (+1) -> False
我试图编写一个函数,它接受list和f函数,并检查列表头部和第二个函数是否为true,然后在迭代器函数中map
该函数应用于列表,但它没有编译,我不知道我的想法是否正确。
这是我最近的尝试:
func xs f1
| null xs = False
| ((head xs) f1)==(head(tail xs))=True
| otherwise = False
iterator l f
| null l = False
| map (func l f) l ==True=True
| otherwise = False
答案 0 :(得分:5)
这是你的意思吗?
iterator :: (Eq a) => [a] -> (a -> a) -> Bool
iterator xs f = and . zipWith (==) xs . iterate f . head $ xs
这符合你的直觉:列表是 迭代所提供函数的结果,从列表的head元素开始。
我们可以写iterator xs f = xs == take (length xs) (iterate f $ head xs)
,但使用length
可以减少在线。如果我们内联==
,take
,length
的定义并将其融合,则结果将是我们的zipWith
代码。
测试:
前奏>迭代器[3,4,5](+1)
真的 前奏>迭代器[2,4,5](+1)
错误
答案 1 :(得分:4)
你真正想做的就是比较
-- with the list [x1, x2, x3, x4] and function f
[f x1, f x2, f x3]
== [ x2, x3, x4]
因此,对于长度为N-1
的列表,会发生N
次比较。使用Prelude
中的函数可以很容易地解决此问题。如果您意识到[x2, x3, x4] == tail xs
和[f x1, f x2, f x3] == map f (init xs)
。由于我们正在比较每个元素,因此我们可以在这两个列表上执行zipWith (==)
,或者我们只需使用list' Eq
实例。但是,我更倾向于使用zipWith
,因为它允许我们删除对init
的调用,因为zipWith
将在列表用完元素时停止。最后一步是将and
结果放在一起,解决方案就完成了:
iterator :: Eq a => [a] -> (a -> a) -> Bool
iterator xs f = and $ zipWith (==) (map f xs) (tail xs)
答案 2 :(得分:1)
这个怎么样:
iterator :: (Eq a) => [a] -> (a -> a) -> Bool
iterator [] _ = error "undefined operation on empty list"
iterator xs f = fst $ foldl foo (True, head xs) (tail xs)
where foo (False, _) b = (False, b)
foo (True, a) b = (b == f a, b)
答案 3 :(得分:0)
coherent :: (a -> a -> Bool) -> [a] -> Bool
coherent p (x : xs@(x2 : _)) | x `p` x2 = coherent p xs
| otherwise = False
coherent _ _ = True
然后
continuous :: Eq a => (a -> a) -> [a] -> Bool
continuous succ = coherent (\ x x2 -> succ x == x2)