haskell类型
一、源文件
介绍这个主要是因为下文很多代码写在源文件中,然后从ghci加载源文件进行测试。
创建一个文本文件,在其中输入,并保存为add.hs文件
-- file: add.hs
add x y = x - y
打开ghci,加载刚才的文件(假设文件目录为e:\haskell\add.hs),命令如下
ghci> :cd e:\haskell
ghci> :load add.hs
ghci> add
二、语言特性
1. 延迟计算
表达式的值在需要用到的时候才被计算,比如在一个文本文档中输入如下,并保存为lazy.hs
-- file: lazy.hs
add x y = if left || right then x + y else x -y
left = True
right = length [..] >
然后加载这个文件,并执行 add 2 1,你会发现结果为3,而不是一直等待计算结果,说明right的值并没有被计算出来。在很多其他语言中(如C#),逻辑或or被特殊处理,从而在左分量为真的时候对右分量短路(short-circuits),而haskell中,(||)运算符只是一个普通的函数,并由于其延迟计算的特性,导致左分量为真的时候,右分量不被计算出来。当然了,haskell中也可以写出短路的逻辑或函数
myOr l r = if l then l else r
haskell中还有一个称作守卫表达式的东东,上面说的myOr函数等价于
-- file: myOr.hs
myOr l r | l = l
myOr l r = r
2. 类型
a) 函数类型
我们看take函数的类型
ghci> :type take
take :: Int -> [a] -> [a]
符号->是右结合的,即,类型说明等价于
take :: Int -> ([a] -> [a])
b)代数数据类型
定义一个新的数据类型
-- file: Object.hs
data ObjectProperty = Object Int String [String]
deriving (Show)
这个类型ObjectProperty与三元组(Int, String, [String])的元素相同,然而haskell认为它们类型不相同。如果要定义一个ObjectProperty类型变量,
ghci> let object = Object "i" ["j", "k"]
ghci> :type it
it :: ObjectProperty
ghci> :type Object
Object :: Int -> String -> [String] -> ObjectProperty
分析: Object是值(数据)构造器,ObjectProperty是对象类型,当然,也可以将对象类型与值构造器写成相同的,如
data Object = Object Int String [String]
然而两者仅仅是名称相同而已。
对于Object的元素分别为Int,String等类型,还可以自定义这些类型的同义类型,如下
-- file: Object.hs
type ObjectId = Int
type ObjectName = String
type ObjectFields = [String]
data Object = Object ObjectId ObjectName ObjectFields
其实跟C++中的typedef关键字类似。
可以查看值构造器Object的类型(是一个函数)
ghci> :type Object
Object :: ObjectId -> ObjectName -> ObjectFields -> Object
由于Object类型中元素是匿名的,可以通过匹配来获取元素值,例如
ghci> let object = Object "a" ["b", "c"]
ghci> let Object x y z = object
ghci> x ghci> :type x
x :: ObjectId
c)枚举类型
-- file: Roygbiv.hs
data Roygbiv = Red
| Orange
| Yellow
| Green
| Blue
deriving (Eq, Show)
其中Red、Orange等都为值构造器
d) 记录类型
前面简单介绍过模式匹配。比如想内窥一下Object(前文介绍的自定义代数数据类型)的内部元素,则可以使用模式匹配,我们这次定义一个函数来获取某个元素
getId (Object id _ _) = id
getName (Object _ name _) = name
getFields (Object _ _ fields) = fields
然而这种方法还是显得代码大块,看起来不爽。
可以定义记录类型,如下
-- file: Object.hs
data Object = Object {
oid :: Int,
oname :: String,
ofields :: [String]
} deriving (Show)
这个类型定义其实跟下面的形式几乎相同
-- file: Object.hs
data Object = Object Int String [String]
deriving (Show) getId :: Object -> Int
getId (Object id _ _) = id getName :: Object -> String
getName (Object _ name _) = name getFields :: Object -> [String]
getFields (Object _ _ fields) = fields
加载上面那个文件时,依然可以向以前那么使用Object类型
ghci> let object = Object "az" ["b"]
或者如下使用
ghci> -- order of elements can be varied
ghci> let object = Object{oid = , ofields = ["i"], oname="str"}
e)参数化类型
跟C#中的泛型类似。比如定义一个类型MyMaybe如下(注意与Prelude模块中的Maybe区分,虽然功能类似)
-- file: Maybe.hs
data MyMaybe a = MyJust a
| MyNothing
这里a就是参数化类型,a可以是String或者Int等,还可以是MyMaybe类型,即嵌套
ghci> let a = MyJust
ghci> let b = Just a
ghci> :type b
b :: Num a => Maybe (MyMaybe a)
f)递归类型
haskell中的List类型与C#中的不同,它是一个递归类型,如下
-- file: MyList.hs
data MyList a = Cons a (MyList a)
| Empty
deriving (Show)
这样设计,使得对其进行递归计算方便。
比如获取List的首项,可以写成如下
-- append to the former MyList.hs file end x = Empty
y = Cons x myHead (Cons i j) = i
myHead Empty = error "MyList.myHead: empty list"
这里对Empty获取首项会抛出一个错误,这样处理还是可以的,我们不能返回Empty,否则跟myHead的第一个计算式的返回类型不同(第一个计算式返回类型为a,而Empty类型为MyList a)。不过,如果结合Maybe类型,或者上面介绍的MyMaybe类型,则可以避免抛出错误,从而使得代码更好看些。处理如下
myHead (Cons i j) = MyJust i
myHead Empty = MyNothing
haskell类型的更多相关文章
- 《Two Dozen Short Lessons in Haskell》(二十四)代数类型
这是<Two Dozen Short Lessons in Haskell>这本书的最后一章,第23章没有习题. 这一章里介绍了Haskell如果自定义一种类型,并且用一个双人博弈游戏为例 ...
- [Real World Haskell翻译]第21章 使用数据库
第21章 使用数据库 从网络论坛到播客采集软件甚至备份程序的一切频繁地使用持久存储的数据库.基于SQL的数据库往往是相当方便:速度快,可扩展从微小到巨大的尺寸,可以在网络上运行,经常帮助处理锁定和事务 ...
- Scala 的确棒
我的确认为计算机学院应该开一门 Scala 的语言课程. 在这篇文章中,我会讲述为什么我会有这样的想法,在此之前,有几点我想要先声明一下: 本文无意对编程语言进行评比,我要讲述的主体是为什么你应该学习 ...
- 函数式编程-将Monad(单子)融入Swift
前言 近期又开始折腾起Haskell,掉进这个深坑恐怕很难再爬上来了.在不断深入了解Haskell的各种概念以及使用它们去解决实际问题的时候,我会试想着将这些概念移植到Swift中.函数式编程范式的很 ...
- 初识Haskell 五:自定义数据类型和类型类
对Discrete Mathematics Using a Computer的第一章Introduction to Haskell进行总结.环境Windows 自定义数据类型 data type de ...
- 初识Haskell 二:基本操作符、类型Type、数据结构
对Discrete Mathematics Using a Computer的第一章Introduction to Haskell进行总结.环境Windows 1. 在安装了ghci后,便可以进行Ha ...
- 「Haskell 学习」二 类型和函数(上)
随着学习的深入,笔记会补充和修订.当然,这个补充修订也许会鸽,但我一定会坚持写完. 这个笔记假定你至少学过C/C++及Python,或与这两种语言类型相同的语言. 类型系统概述 “Haskell’s ...
- ghci对haskell的类型推导
今天这篇文章分析一下ghci交互解释器对类型的推导. 假设有函数fn定义如下: let fn = map map 现在fn的类型是: map map :: [a -> b] -> [[a] ...
- Haskell 函数式编程快速入门【草】
什么是函数式编程 用常规编程语言中的函数指针.委托和Lambda表达式等概念来帮助理解(其实函数式编程就是Lambda演算延伸而来的编程范式). 函数式编程中函数可以被非常容易的定义和传递. Hask ...
随机推荐
- Apache server for win解压版的安装与配置
下载地址: Apache 2.4.16 Win64位:VC14:http://www.apachelounge.com/download/VC14/binaries/httpd-2.4.16-win6 ...
- jQuery事件命名空间
先看一些代码: 也可以用bind进行事件绑定.我们看到上面的代码,我们可以在事件后面,以点号,加我们的名字,就是事件命名空间.所谓事件命名空间,就是事件类型后面以点语法附加一个别名,以便引用事件,如& ...
- NTSC色域(CIE1931)计算公式
色域(CIE1931)=ABS(RC[-6]*RC[-3]+RC[-4]*RC[-1]+RC[-2]*RC[-5]-RC[-6]*RC[-1]-RC[-4]*RC[-5]-RC[-2]*RC[-3]) ...
- http状态码200,300,404等是什么意思
在学习网页设计的时候都应该知道状态码,但我们常见的状态码都是200,404,下面介绍其他的状态值 1开头的http状态码 表示临时响应并需要请求者继续执行操作的状态代码. 100 (继续) 请求者 ...
- java基础:int和integer区别
int是基础数据类型: integer是包装类,里面包含一些基础的方法,最常见的就是数据转换: 比如int转String: int a=0: String b=Integer.toString(a):
- WebTours服务的启动
简介: HP loadrunner自带的一个飞机系统订票网站. 启动服务的步骤: 1.启动StartServer.bat 所在的路径: (\HP LoadRunner 12.02 Community ...
- wpf 寻找某个控件下的子控件
/// <summary> /// 寻找某个控件下的子控件 /// </summary> /// <typeparam name="ChildType" ...
- (89c51)16x16点阵屏幕的实现
基本组件是一个51单片机,一个74154译码器,四个MATRIX-8X8. 考虑到单片机引脚有限,所以使用P0口和P2口的总共16根引脚选择列,而P1口的低4位接译码器,译出的一个低电平选择行.所以图 ...
- .net程序在无.net环境下运行
看了篇文章 测试了下竟然真的可以运行 测试环境是XP下 没有装NET2.0的情况下 可以运行的 不过需要每次输入命令才能运行 点击后还是会报错 原文如下 众所周知,.net程序必须运行在.n ...
- spring 四种依赖注入方式以及注解注入方式
平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程 ...