Haskell 组合运算符

Haskell 组合运算符

组合运算符
Haskell 提供了一个操作符。 将两个函数的组合作为单个函数返回
换句话说,h x = f (g x) 可以写成 h = f.g
例如,odd n = not (even n) 可以改写为 odd = not.even

使用文件夹返回地图(Back to map with foldr)
我们的解决方案是:

map :: (a -> b) -> [a] -> [b]
map f = foldr (\x ys -> f x : ys) []

相反,可以简单地写:

map f = foldr ((:) . f) []
sum = foldr (+) 0
Sum [1,2] = ((+) 1 foldr (+) 2)
Map (+2) [1,2] = (:).(+2) 1 foldr ((:).f) [2]
				= (:)(1+2) foldr…
				= (1+2) : folder…

组合运算符的类型
在这里插入图片描述
这是什么意思?
运算符有两个参数
第一个参数是一个接受类型 b 并返回类型 c 的函数
第二个参数是一个函数,它接受一个类型a并返回一个类型b(这个函数的应用程序的输出是第一个参数函数的输入)
返回值是一个函数,它接受 a 类型的参数并返回 c 类型的值
(a、b 和 c 都可以是同一类型,或混合类型)

链式组合
运算符采用两个函数并将它们组合起来;但请记住,返回的本身就是一个函数
因此,您可以将运算符应用于此结果,以将其与另一个函数结合起来,依此类推
测试:这个函数有什么作用?
mystery xs = sum . map (^2) . filter even xs
在 xs 中选择偶数 ,并每个乘以2, 最后将所有数字相加

为什么要使用组合运算符?
你不必; 这只是简写
事实上,你可能会争辩说,有时用原来的东西更容易理解,但有时速记更容易:

map f = foldr (\x ys -> f x : ys) []
map f = foldr ((:) . f) []

如果您要“在野外”使用函数式编程,您至少需要能够理解它
经验丰富的函数式程序员喜欢它的简洁性

付诸实践:投票算法
我们将研究使用两种不同投票算法计算获胜者的函数式编程解决方案:
先过帖子得票最多的候选人为获胜者
替代投票 每个选民都可以根据自己的喜好投票给尽可能多或尽可能少的候选人,并在他们的选票上按优先顺序列出他们。 计数经历多个阶段:
所有选票均按他们的第一偏好计算。
优先选择票数最少的候选人被淘汰。 该候选人的选票将根据下一个最高偏好重新分配。 (没有次高优先级的投票文件将被删除。)
重复步骤 2,直到只剩下一个候选人。 这个候选人是赢家。

要记录投票,我们只需要知道每个人的选择。 我们可以将其存储为列表,例如
[“Red”, “Blue”, “Green”, “Blue”, “Blue”, “Red”] 这表示候选人 Green 有 1 票,Red 有 2 票,Blue 有 3 票(同样是 优胜者)。
让我们定义一个类型来反映这一点:
type Votes = [String]

从逻辑上思考我们需要做什么:
对于每个候选人,计算他们获得了多少票,按收到的票数排序,返回得票最多的候选人姓名

所以……我们需要一些功能!
候选人 - 从投票列表中获取唯一的候选人
计票– 计算特定候选人的票数
排序 – 对计数进行排序
获胜者——获得获胜者

对于候选人这个功能,我们只需要在投票列表中找到唯一的项目。 我们有几种方法可以做到这一点。 这是一个:

candidates :: Votes -> [String]
candidates [] = []
candidates (x:xs) = x : filter (/= x) (candidates xs)

或者,如果您愿意:
candidates (x:xs) = x : candidates (filter (/= x) xs)

计票
在这里插入图片描述
或者使用函数组合:
在这里插入图片描述
但我需要计算每个候选人
在这里插入图片描述
如果已排序,此结果会更有用……
在这里插入图片描述
最后,胜利者

winner :: Votes -> String
winner = snd . last . result

其他投票方案呢?
同样,让我们从输入的样子开始:
在这里插入图片描述
适合的类型:type Preferences = [[String]]

现在,再次执行该程序:
所有选票均按他们的第一偏好计算。
优先选择票数最少的候选人被淘汰。 该候选人的选票将根据下一个最高偏好重新分配。 (没有次高优先级的投票文件将被删除。)
重复步骤 2,直到只剩下一个候选人。 这个候选人是赢家。

按首选项排序只是将 FPTP 中的结果函数应用于每个首选项列表的头部:

rank :: Preferences -> [String]
rank = map snd . result . map head

rank 返回一个候选人列表,从最不喜欢到最受欢迎排序。
如果列表中有多个项目,我需要删除最不喜欢的项目,然后重复该过程。
这是一个方便的辅助函数:

elim :: Eq a => a -> [[a]] -> [[a]]
elim x = map (filter (/= x))

删除最不受欢迎的

elimWeakest :: Preferences -> Preferences
elimWeakest prefs = elim weakest prefs
                    where
                    (weakest:rest) = rank prefs

但是只做一次是不够的……我需要继续做,直到只有一个候选人
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值