在两个以上的变量上调用两个变量函数的最佳方法是什么?
例如,给定函数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))
所以使用这个我必须创建一个数组,然后像这样的函数来操作数组。有更好的方法吗?
答案 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
,并且已经为您实施。