Function 高阶函数有什么有趣的用途?
我目前正在学习函数编程课程,我对高阶函数和一等公民函数的概念很感兴趣。然而,我还想不出有多少实用的、概念上惊人的、或者只是简单有趣的高阶函数。(除了典型且相当单调的Function 高阶函数有什么有趣的用途?,function,haskell,functional-programming,combinators,higher-order-functions,Function,Haskell,Functional Programming,Combinators,Higher Order Functions,我目前正在学习函数编程课程,我对高阶函数和一等公民函数的概念很感兴趣。然而,我还想不出有多少实用的、概念上惊人的、或者只是简单有趣的高阶函数。(除了典型且相当单调的映射,过滤器等功能) 你知道这样有趣的函数的例子吗? 可能是返回函数的函数,返回函数列表(?)的函数,等等 我很欣赏Haskell的例子,这是我目前正在学习的语言:)这里有几个例子: 我还推荐这本书:这是对所有Haskell的伟大介绍,涵盖了高阶函数 高阶函数通常使用累加器,因此在从较大的列表中形成符合给定规则的元素列表时可以使用它。
映射
,过滤器
等功能)
你知道这样有趣的函数的例子吗?
可能是返回函数的函数,返回函数列表(?)的函数,等等
我很欣赏Haskell的例子,这是我目前正在学习的语言:)这里有几个例子: 我还推荐这本书:这是对所有Haskell的伟大介绍,涵盖了高阶函数
高阶函数通常使用累加器,因此在从较大的列表中形成符合给定规则的元素列表时可以使用它。您注意到Haskell没有循环语法吗?当或执行或时,无
。因为这些都是高阶函数:
map :: (a -> b) -> [a] -> [b]
foldr :: (a -> b -> b) -> b -> [a] -> b
filter :: (a -> Bool) -> [a] -> [a]
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
iterate :: (a -> a) -> a -> [a]
iterate :: (a -> a) -> a -> [a]
takeUntilIncluding -- not a standard function
takeWhile :: (a -> Bool) -> [a] -> [a]
all :: (a -> Bool) -> [a] -> Bool
map :: (a -> b) -> [a] -> [b]
(.) :: (b -> c) -> (a -> b) -> a -> c
(>>=) :: Monad m => m a -> (a -> m b) -> m b
高阶函数取代了控制结构语言中对烘焙语法的需求,这意味着几乎每个Haskell程序都使用这些函数——这使它们非常有用
它们是实现良好抽象的第一步,因为我们现在可以将自定义行为插入到通用骨架函数中
特别是,只有当我们能够链接在一起并操纵函数来创建程序时,才有可能实现这些功能
事实上,当生活是第一流的时候,它是相当无聊的。只有当你有了更高阶的函数,编程才会变得有趣。更高阶的函数也是咖喱菜所必需的,Haskell在任何地方都会用到。从本质上讲,一个带两个参数的函数相当于一个带一个参数的函数,返回另一个带一个参数的函数。当您在Haskell中看到这样的类型签名时:
f :: A -> B -> C
…可以将(>)
读取为右关联,表明这实际上是一个返回类型为B->C
的高阶函数:
f :: A -> (B -> C)
两个参数的非curried函数的类型如下:
f' :: (A, B) -> C
因此,每当您在Haskell中使用部分应用程序时,您都在使用高阶函数。您可以做的一件有趣且有点疯狂的事情是使用函数模拟面向对象系统,并将数据存储在函数的作用域中(即在闭包中)。从某种意义上说,对象生成器函数是一个返回对象的函数(另一个函数),这是高阶的
我的Haskell相当生疏,因此我不能简单地给你一个Haskell示例,但这里有一个简化的Clojure示例,希望能传达这个概念:
(defn make-object [initial-value]
(let [data (atom {:value initial-value})]
(fn [op & args]
(case op
:set (swap! data assoc :value (first args))
:get (:value @data)))))
用法:
(def a (make-object 10))
(a :get)
=> 10
(a :set 40)
(a :get)
=> 40
同样的原理也适用于Haskell(除了可能需要更改set操作以返回新函数,因为Haskell是纯函数)查看Chris Okasaki的论文。它是用ML编写的,但这些思想同样适用于Haskell。当我了解到函数可以是数据结构的一部分时,我真的开始感受到这种力量。这是一个“消费者单子”(technobable:free monad over(i->)
)
因此,一个Coro
可以立即产生一个值,也可以是另一个Coro,具体取决于一些输入。例如,这是一个Coro Int
:
Consume $ \x -> Consume $ \y -> Consume $ \z -> Return (x+y+z)
这将消耗三个整数输入并返回它们的和。您还可以根据输入使其行为不同:
sumStream :: Coro Int Int
sumStream = Consume (go 0)
where
go accum 0 = Return accum
go accum n = Consume (\x -> go (accum+x) (n-1))
这将消耗一个整数,然后在产生整数和之前消耗更多整数。这可以被认为是一个函数,它接受任意多个参数,构造时没有任何语言魔法,只是高阶函数
数据结构中的函数是一个非常强大的工具,在我开始使用Haskell之前,它不是我词汇表中的一部分。下面是一个小片段:
()
是
运算符,(>=)
是do
符号“换行运算符”
在Haskell中编程时,只需使用它们。没有高阶函数的地方是当你意识到它们是多么的有用时。面向对象编程中使用的许多技术都是解决缺少高阶函数的方法
这包括许多在函数式编程中普遍存在的问题。例如,visitor模式是实现应用程序的一种相当复杂的方法。解决方法是使用方法创建一个类,并将该类的元素作为参数传入,以替代传入函数
该模式是另一个方案示例,该方案通常将对象作为参数传递,以替代实际使用的函数
类似地,通常会涉及一些笨拙的方案来传递函数的代理,而直接将函数作为参数传递通常会更好
因此,我的答案是,高阶函数通常用于执行OO程序员执行的相同类型的任务,但是直接执行,并且使用的样板文件要少得多。Joel Spolsky写了一篇演示如何使用Javascript的高阶函数的文章。任何提出这个问题的人都必须阅读。有一件事很有趣,如果不是特别实用的话,那就是。这是一种只使用函数来表示整数的方法。疯狂,我知道。这是我做的。它可能比Lisp/Haskell实现更容易理解。(但老实说,可能不是。JavaScript并不是专门为这类事情设计的。)这里有一个模式,我还没有看到其他人提到过,这在我第一次了解它时让我感到非常惊讶。考虑一个统计软件包,你有一个样本列表作为你的输入,你想计算一堆不同的统计数据。
rays :: ChessPieceType -> [[(Int, Int)]]
rays Bishop = do
dx <- [1, -1]
dy <- [1, -1]
return $ iterate (addPos (dx, dy)) (dx, dy)
... -- Other piece types
-- takeUntilIncluding is an inclusive version of takeUntil
takeUntilIncluding :: (a -> Bool) -> [a] -> [a]
possibleMoves board piece = do
relRay <- rays (pieceType piece)
let ray = map (addPos src) relRay
takeUntilIncluding (not . isNothing . pieceAt board)
(takeWhile notBlocked ray)
where
notBlocked pos =
inBoard pos &&
all isOtherSide (pieceAt board pos)
isOtherSide = (/= pieceSide piece) . pieceSide
iterate :: (a -> a) -> a -> [a]
takeUntilIncluding -- not a standard function
takeWhile :: (a -> Bool) -> [a] -> [a]
all :: (a -> Bool) -> [a] -> Bool
map :: (a -> b) -> [a] -> [b]
(.) :: (b -> c) -> (a -> b) -> a -> c
(>>=) :: Monad m => m a -> (a -> m b) -> m b
statFuncs :: [ [Double] -> Double ]
statFuncs = [minimum, maximum, mean, median, mode, stddev]
runWith funcs samples = map ($samples) funcs
memo :: HasTrie t => (t -> a) -> (t -> a)
@ARGV = map { /\.gz$/ ? "gzip -dc < $_ |" : $_ } @ARGV;
@unempty = grep { defined && length } @many;
@txtfiles = map { $_->[1] }
sort {
$b->[0] <=> $a->[0]
||
lc $a->[1] cmp lc $b->[1]
||
$b->[1] cmp $a->[1]
}
map { -s => $_ }
grep { -f && -T }
glob("/etc/*");
@sorted_lines = map { $_->[0] }
sort {
$a->[4] <=> $b->[4]
||
$a->[-1] cmp $b->[-1]
||
$a->[3] <=> $b->[3]
||
...
}
map { [$_ => reverse split /:/] } @lines;
$sum = reduce { $a + $b } @numbers;
$max = reduce { $a > $b ? $a : $b } $MININT, @numbers;
try {
something();
} catch {
oh_drat();
};
equal :: ((Integer -> Bool) -> Int) -> ((Integer -> Bool) -> Int) -> Bool