3

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

例如给定函数max

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

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

max (max x y) z

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

一种方法是在列表上递归执行(使用“Learn You a Haskell for Great Good”中的示例

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

因此,使用它我必须创建一个数组,然后创建一个这样的函数来对数组进行操作。有一个更好的方法吗?

4

3 回答 3

4

您正在谈论的模式不是“对数组进行操作的函数”,只是一种常见的递归模式。

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

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

如果对列表值的限制打扰您可以使用 foldl', foldl1' 的变体,它将用列表的第一个元素替换种子(0 上)。

maximum xs = foldl1' max xs

几乎每个递归结构都是可折叠的(列表、树、图形...)。
但它们是其他递归模式,可以使用 map 或 filter 加以利用。

无论如何,关于使用折叠的递归的一个很好的介绍,关于折叠
的普遍性和表现力的教程

于 2013-03-18T11:48:21.127 回答
2

只是为了补充 zurgl 的答案,Haskell 有一个用于容器的类型类Foldable 。有一个实用方法

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

简单地定义为

maximum = foldr1 max

因此,对于任何实现的容器类型(Foldable用 换句话说,如果一个数据类型在它的元素上实现了折叠操作,那么在它上面的任何聚合函数都可以用类似的方式定义。ta

于 2013-03-18T13:33:45.703 回答
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 的函数,因此为了模拟这一点,我们编写了一个接受参数列表的函数,[a].

停止。胡歌时间!(a -> a -> a) -> [a] -> a如果您在http://haskell.org/hoogle搜索类型签名,那么您会发现它被调用foldl1并且已经为您实现。

于 2013-03-18T17:25:32.287 回答