haskell模块(modules)
装载模块
Haskell 中的模块是含有一组相关的函数,类型和类型类的组合。而 Haskell 进程的本质便是从主模块中引用其它模块并调用其中的函数来执行操作。这样可以把代码分成多块,只要一个模块足够的独立,它里面的函数便可以被不同的进程反复重用。这就让不同的代码各司其职,提高了代码的健壮性。
Haskell 的标准库就是一组模块,每个模块都含有一组功能相近或相关的函数和类型。有处理 List 的模块,有处理并发的模块,也有处理复数的模块,等等。目前为止我们谈及的所有函数,类型以及类型类都是 Prelude
模块的一部分,它缺省自动装载。在本章,我们看一下几个常用的模块,在开始浏览其中的函数之前,我们先得知道如何装载模块.
在 Haskell中,装载模块的语法为 import
,这必须得在函数的定义之前,所以一般都是将它置于代码的顶部。无疑,一段代码中可以装载很多模块,只要将 import
语句分行写开即可。装载 Data.List
试下,它里面有很多实用的 List 处理函数.
执行 import Data.List
,这样一来 Data.List
中包含的所有函数就都进入了全局命名空间。也就是说,你可以在代码的任意位置调用这些函数.Data.List
模块中有个 nub
函数,它可以筛掉一个 List 中的所有重复元素。用点号将 length
和 nub
组合: length 。nub
,即可得到一个与 (\xs -> length (nub xs))
等价的函数。
import Data.List
numUniques :: (Eq a) => [a] -> Int
numUniques = length 。nub
你也可以在 ghci 中装载模块,若要调用 Data.List
中的函数,就这样:
ghci> :m Data.List
若要在 ghci 中装载多个模块,不必多次 :m
命令,一下就可以全部搞定:
ghci> :m Data.List Data.Map Data.Set
而你的进程中若已经有包含的代码,就不必再用 :m
了.
如果你只用得到某模块的两个函数,大可仅包含它俩。若仅装载 Data.List
模块 nub
和 sort
,就这样:
import Data.List (nub,sort)
也可以只包含除去某函数之外的其它函数,这在避免多个模块中函数的命名冲突很有用。假设我们的代码中已经有了一个叫做nub
的函数,而装入 Data.List
模块时就要把它里面的 nub
除掉.
import Data.List hiding (nub)
避免命名冲突还有个方法,便是 qualified import
,Data.Map
模块提供一了一个按键索值的数据结构,它里面有几个和Prelude
模块重名的函数。如 filter
和 null
,装入 Data.Map
模块之后再调用 filter
,Haskell 就不知道它究竟是哪个函数。如下便是解决的方法:
import qualified Data.Map
这样一来,再调用 Data.Map
中的 filter
函数,就必须得 Data.Map.filter
,而 filter
依然是为我们熟悉喜爱的样子。但是要在每个函数前面都加 个Data.Map
实在是太烦人了! 那就给它起个别名,让它短些:
import qualified Data.Map as M
好,再调用 Data.Map
模块的 filter
函数的话仅需 M.filter
就行了
要浏览所有的标准库模块,参考这个手册。翻阅标准库中的模块和函数是提升个人 Haskell 水平的重要途径。你也可以各个模块的源代码,这对 Haskell 的深入学习及掌握都是大有好处的.
检索函数或搜寻函数字置就用 Hoogle,相当了不起的 Haskell 搜索引擎! 你可以用函数名,模块名甚至类型声明来作为检索的条件.
........................
建立自己的模块
我们已经见识过了几个很酷的模块,但怎样才能构造自己的模块呢? 几乎所有的编程语言都允许你将代码分成多个文件,Haskell 也不例外。在编程时,将功能相近的函数和类型至于同一模块中会是个很好的习惯。这样一来,你就可以轻松地一个 import
来重用其中的函数.
接下来我们将构造一个由计算机几何图形体积和面积组成的模块,先从新建一个 Geometry.hs
的文件开始.
在模块的开头定义模块的名称,如果文件名叫做 Geometry.hs
那它的名字就得是 Geometry
。在声明出它含有的函数名之后就可以编写函数的实现啦,就这样写:
module Geometry
( sphereVolume
,sphereArea
,cubeVolume
,cubeArea
,cuboidArea
,cuboidVolume
) where
如你所见,我们提供了对球体,立方体和立方体的面积和体积的解法。继续进发,定义函数体:
module Geometry
( sphereVolume
,sphereArea
,cubeVolume
,cubeArea
,cuboidArea
,cuboidVolume
) where
sphereVolume :: Float -> Float
sphereVolume radius = (4.0 / 3.0) * pi * (radius ^ 3)
sphereArea :: Float -> Float
sphereArea radius = 4 * pi * (radius ^ 2)
cubeVolume :: Float -> Float
cubeVolume side = cuboidVolume side side side
cubeArea :: Float -> Float
cubeArea side = cuboidArea side side side
cuboidVolume :: Float -> Float -> Float -> Float
cuboidVolume a b c = rectangleArea a b * c
cuboidArea :: Float -> Float -> Float -> Float
cuboidArea a b c = rectangleArea a b * 2 + rectangleArea a c * 2 + rectangleArea c b * 2
rectangleArea :: Float -> Float -> Float
rectangleArea a b = a * b
标准的几何公式。有几个地方需要注意一下,由于立方体只是长方体的特殊形式,所以在求它面积和体积的时候我们就将它当作是边长相等的长方体。在这里还定义了一个 helper
函数,rectangleArea
它可以通过长方体的两条边计算出长方体的面积。它仅仅是简单的相乘而已,份量不大。但请注意我们可以在这一模块中调用这个函数,而它不会被导出! 因为我们这个模块只与三维图形打交道.
当构造一个模块的时候,我们通常只会导出那些行为相近的函数,而其内部的实现则是隐蔽的。如果有人用到了 Geometry
模块,就不需要关心它的内部实现是如何。我们作为编写者,完全可以随意修改这些函数甚至将其删掉,没有人会注意到里面的变动,因为我们并不把它们导出.
要使用我们的模块,只需:
import Geometry
将 Geometry.hs
文件至于用到它的进程文件的同一目录之下.
模块也可以按照分层的结构来组织,每个模块都可以含有多个子模块。而子模块还可以有自己的子模块。我们可以把 Geometry
分成三个子模块,而一个模块对应各自的图形对象.
首先,建立一个 Geometry
文件夹,注意首字母要大写,在里面新建三个文件
如下就是各个文件的内容:
sphere.hs
module Geometry.Sphere
( volume
,area
) where
volume :: Float -> Float
volume radius = (4.0 / 3.0) * pi * (radius ^ 3)
area :: Float -> Float
area radius = 4 * pi * (radius ^ 2)
cuboid.hs
module Geometry.Cuboid
( volume
,area
) where
volume :: Float -> Float -> Float -> Float
volume a b c = rectangleArea a b * c
area :: Float -> Float -> Float -> Float
area a b c = rectangleArea a b * 2 + rectangleArea a c * 2 + rectangleArea c b * 2
rectangleArea :: Float -> Float -> Float
rectangleArea a b = a * b
cube.hs
module Geometry.Cube
( volume
,area
) where
import qualified Geometry.Cuboid as Cuboid
volume :: Float -> Float
volume side = Cuboid.volume side side side
area :: Float -> Float
area side = Cuboid.area side side side
好的! 先是 Geometry.Sphere
。注意,我们将它置于 Geometry
文件夹之中并将它的名字定为 Geometry.Sphere
。对 Cuboid 也是同样,也注意下,在三个模块中我们定义了许多名称相同的函数,因为所在模块不同,所以不会产生命名冲突。若要在 Geometry.Cube
使用 Geometry.Cuboid
中的函数,就不能直接 import Geometry.Cuboid
,而必须得qualified import
。因为它们中间的函数名完全相同.
import Geometry.Sphere
然后,调用 area
和 volume
,就可以得到球体的面积和体积,而若要用到两个或更多此类模块,就必须得qualified import
来避免重名。所以就得这样写:
import qualified Geometry.Sphere as Sphere
import qualified Geometry.Cuboid as Cuboid
import qualified Geometry.Cube as Cube
然后就可以调用 Sphere.area
,Sphere.volume
,Cuboid.area
了,而每个函数都只计算其对应物体的面积和体积.
以后你若发现自己的代码体积庞大且函数众多,就应该试着找找目的相近的函数能否装入各自的模块,也方便日后的重用.
转自:http://learnyouahaskell-zh-tw.csie.org/zh-cn/modules.html
haskell模块(modules)的更多相关文章
- vue第二十单元(vux的配置中模块modules的用法)
第二十单元(vux的配置中模块modules的用法) #课程目标 1.什么是module? 2.怎么用module? 3.样板代码目录结构 #知识点 #1.modules 在Vue中State使用是单 ...
- yii2 创建模块modules
方案一:如果模块儿较少,不用专门给模块儿目录定义别名,酱紫做就ok啦. 1.在项目根目录下面创建一个 modules 目录. 2.进入 gii : http://localhost/basic/web ...
- python 3环境下,离线安装模块(modules)
说明: 需要在环境中安装python的模块,但是无法联网,就通过在Pypi上下载离线模块的包进行安装 安装过程: 1.下载模块,如PyMySQL-0.9.3.tar.gz,下载地址:https://f ...
- 03 深入远程执行:target目标、模块modules、返回returns
0.学习目的 http://docs.saltstack.cn/topics/execution/index.html 官方文档 0.1 命令解释 [root@host---- ~]# salt ' ...
- webpack学习之——模块(Modules)
在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为模块. 每个模块具有比完整程序更小的接触面,使得校验.调试.测试轻而易举. 精 ...
- Lua标准库- 模块(Modules)
Lua包库为lua提供简易的加载及创建模块的方法,由require.module方法及package表组成 1.module (name [, ···]) 功能:建立一个模块. module的处理流程 ...
- 深入浅出ES6(十六):模块 Modules
作者 Jason Orendorff github主页 https://github.com/jorendorff 早在2007年我刚加入Mozilla的JavaScript团队的时候广为流传一个 ...
- Yii2 在模块modules间跳转时,url自动加模块名
如目的地址product/detail, 当前模块是admin, 访问时如果目的url'product/detail',会变成'admin/product/detail'. 解决方法:url改成'/p ...
- PyQt5 模块modules
The QtCore module contains the core non-GUI functionality. This module is used for working with time ...
随机推荐
- 网站优化的经验和技巧--精简高效的C#
对大型网站,技术涉及面非常广,对硬件,软件,编程语言,Web Service,防火墙等等有很高要求. 面对大量用户,高并发请求,可以使用高性能服务器,高性能编程语言,高性能数据库,加大带宽等,这 ...
- radio的change事件
radio的change事件 <scripttype="text/javascript"> $(document).ready(function(){ $(" ...
- LAMP网站架构方案分析
本文引自:http://www.williamlong.info/archives/1908.html LAMP(Linux-Apache-MySQL-PHP)网站架构是目前国际流行的Web框架,该框 ...
- [转]eclipse github 提交代码
1 git add2 git commit3 git pull (会产生冲突) 分成自动合并和手动合并4 处理冲突的文件 5 git push 本次commit 我用的是Eclipse的插件EGit ...
- Lucene.net项目研究说明
最近项目需要全文检索,所以找了几个开源的.NET检索项目,如:Lucene.net,Sphinx,Hubble.net.最后选择使用Lucene.ne来实现全文检索.至于原因嘛,可以参考下面几点: 1 ...
- 查看oracle 启动了多久
想看一下系统正常运行了多少天?开机多长时间没有重启了? windows系统 C:\>systeminfo |find “系统启动时间”系统启动时间: 265 天 4 小时 26 分 32 ...
- CI 自动操作日志
在控制器中,继承一个总控制器,MY_Controller,让其他集成的控制器,继承my控制器 在MY_Controller控制器中,重写构造方法, 代码如下,测试pass! class MY_Cont ...
- CSS图片去色
.imgFilter { filter: grayscale(100%); -webkit-filter: grayscale(100%); -moz-filter: grayscale(100%); ...
- matlab结构体形式保存数据生成.mat文件< 转>
2015年 参加天池大数据竞赛 为了建立模型,打算基于matlab使用Random Forest Algorithm的工具包 该工具包我在此分享给大家,http://yunpan.cn/cVX ...
- Linux 消息队列编程
消息队列.信号量以及共享内存被称作 XSI IPC,它们均来自system V的IPC功能,因此具有许多共性. 键和标识符: 内核中的每一种IPC结构(比如信号量.消息队列.共享内存)都用一个非负整数 ...