写前缀函数(Haskell)

时间:2015-03-29 23:19:53

标签: haskell

我正在编写一个前缀函数,它将二进制函数和一个数字列表作为参数,并返回一个通过计算连续函数形成的列表并随时累积。 为简单起见,这是一个例子:

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

2 个答案:

答案 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)

以下是hackagescanl所说的内容:

scanl :: (b -> a -> b) -> b -> [a] -> [b] Source

scanlfoldl类似,但会从左侧返回连续减少值的列表:

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函数也会发生同样的情况。希望这会有所帮助。