我正在编写一个前缀函数,它将二进制函数和一个数字列表作为参数,并返回一个通过计算连续函数形成的列表并随时累积。 为简单起见,这是一个例子:
prefix (+) [2, 4, 1, 1]
returns [2, 6, 7, 8]
prefix (+) [0, 2, -3, 4, -5]
returns [0, 2, -1, 3, -2]
prefix max [2, 3, 1, 1]
returns [2, 3, 3, 3]
到目前为止,这是我的代码,但是当我尝试加载文件时出现错误,因为“列表不在范围内”。我怎样才能重写它以便编译器有意义?任何帮助将不胜感激。
prefix' :: (a -> b) -> [a] ->[b]
prefix' _ [] = []
prefix' f (x:xs)
| ((list !! x) == 0) = f (list !! 0) (list !! 0)
| otherwise = prefix' f xs
答案 0 :(得分:3)
试试这个
prefix::(a -> a -> a) -> [a] -> [a]
prefix f lst| null lst = []
| null (tail lst) = lst
| otherwise = h : prefix' f (f h) (tail lst) where
h = head lst
prefix' fn fc (x:xs) | null xs = [acc]
| otherwise = acc : prefix' fn (fn acc) xs where
acc = fc x
我会尝试尽可能多地解释上面的代码。函数的类型签名是一个函数(a->a->a)
和一个列表[a]
作为参数,并返回另一个列表,该函数应用于列表的每个相邻对。参数列表中的a
仅表示任何类型(可以是任何类型)。如果我们指定了特定类型(即在标题情况下),则该函数仅适用于该特定类型
null lst
),如果是,我们只返回一个空列表null (tail lst)
),在这种情况下,我们只返回列表head lst
)的头部并调用另一个我们定义的函数苍蝇要计算列表的其余部分(: prefix' f (f (head lst)) (tail lst)
)。请注意:
将头部与列表的其余部分分开prefix'
函数的类型签名为(a -> a -> a) -> (a -> a) -> [a] -> [a]
,因此您可以看到唯一不同的是它需要一个额外的参数,即一个函数(fc
)获取a
类型的元素并返回类型为a
的元素。为了创建这个函数,我们简单地将一个参数传递给作为参数的初始函数,该函数创建了这个新函数。这将有助于计算列表的其余部分fc
应用于列表中的该元素,并返回包含函数返回值的列表fc
应用于列表的第一个元素,并通过将fc
应用于fn
的返回值来再次生成fc x
。如果您有兴趣了解所有这些是如何运作的,那么这就是我一直在使用的website,并且由于本网站的原因,我对haskell的了解有了很大改善,因此强烈推荐
答案 1 :(得分:3)
您不想实现scanl1
功能吗?我也是初学者,但据我所知,它是这样的:
scanl1 :: (a -> a -> a) -> [a] -> [a]
scanl1 f (x:xs) = scanl f x xs
scanl1 _ [] = []
scanl
功能。 scanl1
使用的是这样的:
scanl :: (b -> a -> b) -> b -> [a] -> [b]
scanl = scanlGo
where
scanlGo :: (b -> a -> b) -> b -> [a] -> [b]
scanlGo f q ls = q : (case ls of
[] -> []
x:xs -> scanlGo f (f q x) xs)
以下是hackage对scanl
所说的内容:
scanl :: (b -> a -> b) -> b -> [a] -> [b] Source
scanl
与foldl
类似,但会从左侧返回连续减少值的列表:
scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
请注意
last (scanl f z xs) == foldl f z xs.
所以,我猜执行流程是这样的:
scanl1 (+) [2, 4, 1, 1]
scanl (+) 2 [4, 1, 1]
scanlGo (+) 2 [4, 1, 1]
2 : scanlGo (+) (+ 2 4) [1, 1]
2 : 6 : scanlGo (+) (+ 6 1] [1]
2 : 6 : 7 : scanlGo (+) (+ 7 1) []
2 : 6 : 7 : 8 : scanlGo []
2 : 6 : 7 : 8 : []
[2, 6, 7, 8]
您提到的(*)
和max
函数也会发生同样的情况。希望这会有所帮助。