当前位置: 首页 > news >正文

《Haskell并行与并发编程》——第2章,第2.4节Deepseq

本节书摘来自异步社区《Haskell并行与并发编程》一书中的第2章,第2.4节Deepseq,作者【英】Simon Marlow,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.4 Deepseq
Haskell并行与并发编程
前面已经用过了force函数,其具体类型如下:
`
force :: NFData a => a -> a`
函数force会对其参数完全求值,然后返回。不过该函数并非内建,而是针对每种数据类型,通过NFData类对该函数的行为进行定义。NFData的意思是范式数据(normal-form data),其中范式是指不包含未被求值子表达式的值,“数据”则表示范式中不包含函数,因为无法看到函数里面的内容并对里面的内容求值1。

类NFData仅包含一个方法:
`
class NFData a where
rnf :: a -> ()
rnf a = a seq ()`
函数rnf名字的意思是“约化为范式”(reduce to normal-form)。该函数对其参数完全求值,然后返回()。默认通过seq来实现,对于没有子结构的类型来说很方便,只需使用默认定义即可。例如:Bool的实例可以简单地定义:

instance NFData Bool
模块Control.Deepseq对库中所有其他的常见类型均提供了实例。

对于自定义的类型,可能需要实现相应的NFData的实例。例如,对于二叉树类型:
`
data Tree a = Empty | Branch (Tree a) a (Tree a)`
那么,其NFData的实例如下:

instance NFData a => NFData (Tree a) where
  rnf Empty = ()
  rnf (Branch l a r) = rnf l `seq` rnf a `seq` rnf r

实现的思路为递归地对数据类型的组成部分应用rnf,然后将这些rnf的调用通过seq组合起来。

Control.DeepSeq模块中还有一些其他运算,例如:

deepseq :: NFData a => a -> b -> b
deepseq a b = rnf a `seq` b

函数deepseq因其和seq的相似性而得名:和seq类似,都是强制求值。如果把弱首范式看成是浅(shallow)求值,那么范式就是深(deep)求值,因此得名deepseq。

函数force是通过deepseq定义的:

force :: NFData a => a -> a
force x = x `deepseq` x

函数force的功能应该被认为是将WHNF转换为NF(normal form),也就是,当程序将force x求值成WHNF时,x会被求值成NF。

图像说明文字将表达式求值为范式需要对整个数据结构进行遍历,因此需要铭记,对于大小为n的数据结构,其复杂度是O(n),而对seq来说,只有O(1)。因此,应该避免对同一数据反复使用force或deepseq函数。

WHNF和NF就像天平的两端,但是,根据数据类型的不同,还有许多处于中间的“不同程度的求值”。例如:前面的length函数对列表的脊(spine)求值,即展开了列表,但未对列表的元素求值。parallel包中的模块Control.Seq提供了一系列组合子,通过组合,可以对数据结构达到不同程度的求值。本书虽然不会在例子中使用这些运算,但对读者也许会有所帮助。

1不过,纯粹为了方便,定义了一个函数的NFData实例,会将函数求值为WHNF(弱首范式),因为经常会有数据结构里面包含函数,而尽管如此,还是想尽可能地对这样的数据结构进行求值。

相关文章:

  • 《C++ AMP:用Visual C++加速大规模并行计算》——3.5 array_view T,N
  • 《用友ERP-U8(V8.72)模拟实战----财务、供应链和生产制造》一1.4 系统管理注册和导入演示账套...
  • 《Unreal Engine 4蓝图可视化编程》一导读
  • 《Splunk智能运维实战》——3.8 使用散点图根据大小和响应时间标识离散的请求...
  • 模块与包
  • 生成模型和判别模型
  • 树莓派+pythonista实时监控系统
  • mysql开发之---使用游标双层嵌套对总表进行拆分为帖子表和回复表
  • window 下安装 wget 命令
  • V8 Ignition:JS 引擎与字节码的不解之缘
  • centos安装vsftp
  • 【zabbix系列】安装与加入host
  • 【Sets】使用Google Guava工程中Sets工具包,实现集合的并集/交集/补集/差集
  • JAVA多线程入门
  • 20145223 杨梦云 《网络对抗》 Web基础
  • 【刷算法】求1+2+3+...+n
  • 345-反转字符串中的元音字母
  • C++类中的特殊成员函数
  • ECMAScript6(0):ES6简明参考手册
  • ES10 特性的完整指南
  • ES6核心特性
  • JavaScript创建对象的四种方式
  • k8s 面向应用开发者的基础命令
  • log4j2输出到kafka
  • PHP面试之三:MySQL数据库
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • Sublime Text 2/3 绑定Eclipse快捷键
  • vuex 笔记整理
  • 从setTimeout-setInterval看JS线程
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 前端路由实现-history
  • 使用docker-compose进行多节点部署
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • $().each和$.each的区别
  • (07)Hive——窗口函数详解
  • (1)常见O(n^2)排序算法解析
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (vue)页面文件上传获取:action地址
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)大型网站架构演变和知识体系
  • **PHP分步表单提交思路(分页表单提交)
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)...
  • .net core 源码_ASP.NET Core之Identity源码学习
  • .NET Reactor简单使用教程
  • .net 反编译_.net反编译的相关问题
  • .net知识和学习方法系列(二十一)CLR-枚举
  • .net中应用SQL缓存(实例使用)
  • @SuppressWarnings注解
  • @test注解_Spring 自定义注解你了解过吗?
  • [145] 二叉树的后序遍历 js