haskell简明入门(一)

简介: 本文的主要内容参考自《Haskell趣学指南》1. What is Haskell?    以下内容引用自Haskell官网:Haskell是一个先进的,纯粹的函数式编程语言。一个典型的声明式地,静态类型的代码如下:primes = filterPrime [2.

本文的主要内容参考自《Haskell趣学指南》

1. What is Haskell?

    以下内容引用自Haskell官网:

Haskell是一个先进的,纯粹的函数式编程语言。一个典型的声明式地,静态类型的代码如下:

primes = filterPrime [2..] 
  where filterPrime (p:xs) = 
          p : filterPrime [x | x <- xs, x `mod` p /= 0]

Haskell 有如下的特性:

  • 静态类型(Statically Typed)。Haskell的每一个表达式都有一个在编译时决定的类型。所有的由函数引用组合起来的类型必须相匹配(match up),否则无法正常编译。类型不仅仅是形式上的保证,更是用于表达程序结构的语言。
  • 纯粹函数式(Purely functional)。Haskell的每一个函数都是数学意义上的(pure)。即使是有副作用的IO操作也不过是在描述在做什么,同样由纯粹的代码产生。没有声明或者指令,仅仅只有表达式,该表达式不能对变量进行修改(局部变量或者全局变量),或者是获取像时间、随机数这样的状态。
  • 类型推断(Type Inference)。你并不需要在Haskell中显式地写出每一种类型,类型将会进行双向推断。当然,你也可以选择自己写出类型,或者让编译为你进行推断。
  • 并发(Concurrent)。Haskell可以很容易进行并发编程,这得力于它可以显式地处理effects。它的王牌编译器GHC带有一个高性能的并行的垃圾回收器,还有一个轻量级的并发库,其中包含了很多的有用的并发函数原型以及抽象接口。
  • 惰性计算(Lazy)。函数并不会直接计算它们的值。这意味着程序可以在一起组合地非常好,可以通过只写通常的函数就表达控制结构(if/else)。Haskell代码的纯粹性使得它可以轻松将函数链式组合,操作起来非常方便。
  • (Packages)。你可以在public packages server 上找到非常多的活跃的开源Haskell packages。

2. How to use Haskell?

    你可以下载Haskell的GHC编译器,该编译器可以解释也可以编译Haskell程序。GHC还有一个很有用的交互模式,在终端输入ghci即可进入交互模式。然后运行命令:l demo.hs就可以加载demo.hs中的函数(Haskell程序文件以hs结尾)。如果你对demo.hs做了修改,可以重新运行命令:l demo.hs以重新加载其中的函数。这是我们以后实验学习Haskell的基本流程。

3. Basic Operations

3.1 基本类型

    在终端输入ghci进行入交互模式。如下是一些基本的运算,几乎不用解释就可以看懂。

Prelude> 2+15
17
Prelude> 45*90
4050
Prelude> 568-23
545
Prelude> 3/2
1.5
Prelude> (90-23)*8
536
Prelude> 50*(100-9028)
-446400
Prelude> True && False
False
Prelude> True && True
True
Prelude> False || True
True
Prelude> not False
True
Prelude> not (True && True)
False
Prelude> 5 == 4
False
Prelude> 5 == 5
True
Prelude> "Hello" == "Hello"
True
Prelude> 5 /= 4
True
Prelude> 5 /= 5
False

3.2 基础函数

3.2.1 Haskell 常用内置函数

  • succ。succ 函数返回一个数的后继。比如:
Prelude> succ 10
11

注意Haskell中函数的调用参数是使用空格的,这一点和传统的编译型语言有很大的不同。

  • pred。pred函数和succ函数相反,它返回一个数字的前驱。比如:
Prelude> pred 10
9
  • min。min函数接收两个数字参数,返回这两个数字的最小值。比如:
Prelude> min 10 3.4
3.4

如果要比较多个数字的最小值,直接传递多个数字作为参数会报错,比如:

Prelude> min 1 19 23
<interactive>:21:1:
    Non type-variable argument in the constraint: Num (a -> t)
    (Use FlexibleContexts to permit this)
    When checking that ‘it’ has the inferred type
      it :: forall a t. (Num a, Num (a -> t), Ord (a -> t)) => t

我们可以通过多次调用min函数(注意需要加括号)来解决:

Prelude> min 1 (min 9 23)
1
  • max。max函数返回两个数字的最大值。比如:
Prelude> max 9.9 9.0
9.9
  • Haskell中函数拥有最高的优先级。下面两句是等效的:
Prelude> succ 10 + max 10 20 * 3
71
Prelude> (succ 10) +(max 10 20)*3
71

注意succ 9*10的值是100而不是91,这是因为计算的顺序是先计算succ 9得到10,然后再计算10*10=100,如果我们要计算9*10的后继,需要写成succ (9*10)的形式。

  • div。div函数计算一个整数除以另外一个整数的结果,比如:
Prelude> div 10 3
3
Prelude> div 10 5
2

需要注意的是,div函数接收的两个参数必须是整数,第一个是被除数,第二个是除数,如果除不尽则返回商,舍弃余数。传入数字不能是浮点数,比如下面的形式会报错:

Prelude> div 1.2 3
<interactive>:31:1:
    No instance for (Fractional a0) arising from a use of ‘it’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Integral a => Fractional (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      instance Fractional Double -- Defined in ‘GHC.Float’
      instance Fractional Float -- Defined in ‘GHC.Float’
    In the first argument of ‘print’, namely ‘it’
    In a stmt of an interactive GHCi command: print it

3.2.2 构建自己的函数

  • doubleMe。doubleMe函数的定义如下:
doubleMe x = x + x -- 将数字变为两倍

这个函数非常简单,就是返回一个数字的两倍。注意上面函数的定义方式:首先是函数名字,然后是空格分隔的参数,接着是等于号,等于号后面的是函数的实现。要运行这个函数,需要把它写在一个文件里,比如add.hs,然后输入ghci进入命令行模式,输入:l add.hs就可以加载函数了。下面是它的调用计算结果:

Prelude> :l add.hs 
[1 of 1] Compiling Main             ( add.hs, interpreted )
Ok, modules loaded: Main.
*Main> doubleMe 2
4
*Main> doubleMe 3
6
  • doubleUs。该函数接收x,y两个参数,然后返回这两个参数之和的两倍。定义如下:
doubleUs x y = x*2 + y*2 -- 两个数字变为两倍然后相加

调用计算结果为:

*Main> doubleUs 1 3
8
*Main> doubleUs 0 2
4
  • useDoubleMe。该函数功能和doubleUs一样,只不过其调用了doubleMe两次,代码如下:
useDoubleMe x y = doubleMe x + doubleMe y -- 调用简单函数

对了,忘了说了,haskell中注释是--

  • doubleSmallNumber。该函数使用if else语句实现的功能是:如果x小于100则返回x;否则返回x的两倍。代码如下:
doubleSmallNumber x = if x < 100 then x else 2*x --如果x小于100返回x,否则返回2*x

调用结果为:

*Main> doubleSmallNumber 20
20
*Main> doubleSmallNumber 200
400

需要注意的是Haskell中if和else一定是一起出现的,else不可以省略,而且本质上if和else都是需要返回一个值。Haskell中所有的函数和表达式都需要返回一个结果,if语句就是一个表达式,所以它一定会返回一个结果。

  • doubleSmallNumber'。doubleSmallNumber'函数(注意函数最后有一个')返回的结果是doubleSmallNumber返回值加1,定义为:
doubleSmallNumber' x = (if x < 100 then x else 2*x) + 1 -- doubleSmallNumber返回值加1

我们通常在Haskell中在函数名字最后加一个'来表示对某个函数稍微修改之后得到的新函数。上面的函数如果把括号去掉,那么只会在x>=100的时候加1了。另外需要注意的是,Haskell的函数名字开头不能是大写字母。

  • conanO'Brien。conanO'Brien是一个没有参数的函数,这样的函数也被称为"定义"或者"名字"。conanO'Brien定义如下:
conanO'Brien = "It's a-me, Conan O'Brien!" -- 没有参数的函数

上面的conanO'Brien函数定义好了之后,conanO'Brien就与字符串"It's a-me, Conan O'Brien!"等价了,而且字符串的值是不可以修改的。

热爱编程,热爱机器学习! github:http://www.github.com/Lyrichu github blog:http://Lyrichu.github.io 个人博客站点:http://www.movieb2b.com(不再维护)
目录
相关文章
|
7月前
|
安全 应用服务中间件 网络安全
从零(服务器、域名购买)开始搭建雷池WAF到应用上线简明指南
本文详细介绍了基于雷池WAF的网站防护部署全流程,涵盖服务器与域名准备、WAF安装配置、网站接入设置及静态文件站点搭建等内容。通过最低1核CPU/1GB内存的服务器配置,完成Docker环境搭建、雷池一键安装及端口设置,实现域名解析、SSL证书配置和防护策略优化。同时支持301重定向与HTTP到HTTPS自动跳转,确保访问安全与规范。最后还提供了使用静态文件搭建网站的方法,帮助用户快速构建具备基础WAF防护能力的网站系统。
从零(服务器、域名购买)开始搭建雷池WAF到应用上线简明指南
|
10月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
2037 5
|
10月前
|
存储 人工智能 安全
有奖体验 AI 模特换装,解锁电商视觉新体验
有奖体验 AI 模特换装,解锁电商视觉新体验
有奖体验 AI 模特换装,解锁电商视觉新体验
|
存储 数据采集 物联网
物联网技术在物流领域的应用会遇到哪些挑战?
物联网技术在物流领域的应用会遇到哪些挑战?
735 60
|
存储 编解码 人工智能
【AI系统】FBNet 系列
本文介绍了FBNet系列的三种版本,从FBNetV1基于NAS的轻量级网络设计,到FBNetV2通过DMaskingNAS增加搜索空间,再到FBNetV3联合搜索网络结构与训练参数,展示了如何利用NAS技术优化网络结构和提升模型性能。文章详细解释了各版本的技术特点和实现方法,为读者提供了深入了解和应用NAS技术的宝贵资料。
272 10
【AI系统】FBNet 系列
|
存储 数据可视化 项目管理
RNA-seq 差异分析的细节详解 (5)
RNA-seq 差异分析的细节详解 (5)
RNA-seq 差异分析的细节详解 (5)
|
10月前
|
人工智能 自然语言处理 IDE
情人节用 DeepSeek+通义灵码玩花样!在 IDE 中使用满血版 DeepSeek R1 试试
情人节用 DeepSeek+通义灵码玩花样!在 IDE 中使用满血版 DeepSeek R1 试试
|
机器学习/深度学习 数据可视化 数据挖掘
Jupyter Notebook交互式开源笔记本工具
Jupyter Notebook交互式开源笔记本工具
368 1
|
存储 运维 监控
Elasticsearch Serverless 高性价比智能日志分析关键技术解读
本文解析了Elasticsearch Serverless在智能日志分析领域的关键技术、优势及应用价值。
690 8
Elasticsearch Serverless 高性价比智能日志分析关键技术解读
|
存储 C语言
C语言中a 和&a 有什么区别
在C语言中,&quot;a&quot; 是一个变量的名字,代表存储在内存中的某个值。而&quot;&a&quot; 则是获取该变量的内存地址,即变量a在计算机内存中的具体位置。这两者的主要区别在于:&quot;a&quot; 操作的是变量中的值,&quot;&a&quot; 操作的是变量的内存地址。
2031 23