Haskell:在N变量上调用两个变量的函数

时间:2013-03-18 11:26:14

标签: haskell

在两个以上的变量上调用两个变量函数的最佳方法是什么?

例如,给定函数max

Prelude> :t max
max :: Ord a => a -> a -> a

如果我想要最大的变量x,y,z,我可以调用

max (max x y) z

但是对于大量元素来说它很冗长。

一种方法是在列表上递归执行(使用“了解大好的Haskell”中的示例

maximum :: Ord x => [x] -> x; 
maximum [] = error "maximum of empty list" 
maximum (x:[]) = x
maximum (x:xs) = max x (maximum(xs))

所以使用这个我必须创建一个数组,然后像这样的函数来操作数组。有更好的方法吗?

3 个答案:

答案 0 :(得分:4)

您所谈论的模式不是“在数组上运行的函数”,只是一种常见的递归模式。

当然还有处理递归模式的功能,例如折叠。
然后可以将您的最大功能重新定义为,

maximum xs = foldl' max 0 xs -- assuming all the value are upper than 0.   

如果对列表值的限制令人烦恼,你可以使用foldl',foldl1'的变体,它将替换种子(0 upper),列表的第一个元素。

maximum xs = foldl1' max xs

几乎每个递归结构都是可折叠的(List,Tree,Graph ......) 但它们是其他递归模式,可以使用map或filter进行利用。

无论如何,使用fold进行递归的很好的介绍,
A tutorial on the universality and expressiveness of fold

答案 1 :(得分:2)

为了添加zurgl的答案,Haskell为容器提供了类型Foldable。有一种实用方法

maximum :: (Foldable t, Ord a) => t a -> a

简单定义为

maximum = foldr1 max

因此,对于实现Foldable(由t表示)的任何容器类型以及具有排序(a)的任何元素类型,都可以使用此单个函数。换句话说,如果数据类型对其元素实现折叠操作,则可以以类似的方式定义其上的任何聚合函数。

答案 2 :(得分:1)

  

在两个以上的变量上调用两个变量函数的最佳方法是什么?

好吧,让我们看看这里。在Racket中,我会说使用宏。

#lang racket

(define-syntax apply*
  (syntax-rules ()
    [(apply* f x y)
     (f x y)]
    [(apply* f x y rest ...)
     (apply* f (f x y) rest ...)]))

(define (plus a b) (+ a b))
(apply* plus 1 2 3 4 5) ;; => 15

这里我们认为apply*形式采用两个参数的函数,并在任意长的参数列表上调用它。这将把(apply* max x y z)字面上扩展为(max (max x y) z),允许你编写漂亮的代码并让宏扩展器将其转换为详细代码。


然而,Haskell宏很难处理,而且非常单一。所以让我们改用一个函数。这个功能会是什么样的?

applyStar :: (a -> a -> a) -> [a] -> a

第一个参数是一个2-arg函数,它接受两个相同类型的东西,并吐出一个这种类型的东西。我们可以从期望的结果中看到:max (max x y) z,输出必须与输入的类型相同。 Haskell不允许你定义变量arity的函数,所以为了模拟它,我们编写了一个带有 list 参数的函数[a]

停止。霍格时间!如果您在http://haskell.org/hoogle搜索类型签名(a -> a -> a) -> [a] -> a,那么您会发现这个名为foldl1,并且已经为您实施。