haskell模块(modules)

摘要:
加载模块Haskell中的模块是一组相关函数、类型和类型类的组合。Haskell过程的本质是从主模块引用其他模块,并调用其中的函数来执行操作。阅读标准库中的模块和函数是提高个人Haskell水平的重要途径。在声明其包含的函数名后,可以按如下方式编写函数实现:moduleGeometry,如您所见,我们为球体、立方体和立方体的面积和体积提供了解决方案。

装载模块

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 importData.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

haskell模块(modules)第1张

标准的几何公式。有几个地方需要注意一下,由于立方体只是长方体的特殊形式,所以在求它面积和体积的时候我们就将它当作是边长相等的长方体。在这里还定义了一个 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.areaSphere.volumeCuboid.area 了,而每个函数都只计算其对应物体的面积和体积.

以后你若发现自己的代码体积庞大且函数众多,就应该试着找找目的相近的函数能否装入各自的模块,也方便日后的重用.

转自:http://learnyouahaskell-zh-tw.csie.org/zh-cn/modules.html

免责声明:文章转载自《haskell模块(modules)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Android、iOS、和Web如何做灰度发布?C3P0数据库Jar包的使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Haskell语言学习笔记(23)MonadReader, Reader, ReaderT

MonadReader 类型类 class Monad m => MonadReader r m | m -> r where ask :: m r ask = reader id local :: (r -> r) -> m a -> m a reader :: (r -> a)...

Centos安装shellcheck的方法

shellcheck shellcheck是用来检查shell脚本的工具。 采用haskell语言开发。 在ubuntu中,可以直接采用apt install shellcheck安装完成 但是在Centos,yum是没有shellcheck的包的,因此,需要另一种方法安装 Centos安装shellcheck 由于shellcheck是haskell语...

Haskell 差点儿无痛苦上手指南

趁着自己重装Linux 虚拟机的机会,把安装 haskell 的过程记录一下,顺便帮那些还犹豫徘徊在haskell门外的读者入门。 基本概念: Haskell : 是一门通用函数式语言,差点儿能够进行不论什么种类的开发,包含命令行,GUI,数据库,Web.源码能够跨平台: Linux,Mac, Windows, FreeBSD 等. Haske...

Python Twisted 学习系列21(转载stulife最棒的Twisted入门教程)

第二十一部分 惰性不是迟缓: Twisted和Haskell 简介 在上一个部分我们对比了Twisted与 Erlang,并将注意力集中在它们共有的一些思想上.结果表明使用Erlang也是非常简便的,因为异步I/O和反应式编程是Erlang运行时和进程模型的关键元素. 今天我们想走得更远一点,去看一看 Haskell —— 另一种功能性语言,然而与Erla...

Haskell语言学习笔记(22)MaybeT

Monad Transformers Monad 转换器用于将两个不同的Monad合成为一个Monad。Monad 转换器本身也是一个 Monad。 MaybeT MaybeT 这个 Monad 转换器通过将 Maybe Monad 封装进其它 Monad来使两者合二为一。 newtype MaybeT m a = MaybeT { runMaybeT :...