• 「Haskell 学习」一 环境与大致了解


    感谢《Real World Haskell》在网上的免费发布,可以白嫖学Haskell这个久闻大名的函数式编程语言了。

    本文运行于openSUSE Tumbleweed下,运行相关命令时留意。

    安装

    Linux下想搞和编程相关的事情非常简单,至少比配置游戏要简单。

    sudo zypper in ghc

    ghc即Glasgow Haskell Compiler,一个主流的编译器。也支持python式的互动执行(ghci)。笔者运行时该编译器已经是8.0.2版本了。

    运行

    输入ghci,会进入Haskell的interactive interpreter。大概的运行界面如下:

    # zuiho @ zuiho-pc in ~ [Time] 
    $ ghci
    GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
    Prelude> 

    根据书中的说法,“The word Prelude in the prompt indicates that Prelude, a standard library of useful functions, is loaded and ready to use. When we load other modules or source files, they will show up in the prompt, too.”即prelude是一个基本模块,初始情况会加载它。而如果加载了其它模块,那么会变成这样:

    Prelude> :module + Data.Ratio
    Prelude Data.Ratio> 

    可想而知,如果加载了114514个模块,那么长度会比较麻烦(但好处是告诉运行者加载了哪些模块)。这本书里面建议了一个方法,来避免这个可能的情况出现:

    Prelude Data.Ratio> :set prompt "ghci> "
    ghci> 

    基本功能

    计算器

    可以当计算器使用,除法不去尾,^与**作为幂次进行计算(前者后跟整数,后者后跟浮点数)。值得一提的是,支持前缀表达式,只要给操作符加上括号:

    ghci> (+) 2 2
    4

    而Haskell中的“-”是一个一元操作符,也就是说,-3的意思是一个数字3再加上前面的减法操作符。这意味着这样的操作会出现问题:

    ghci> 22 + -33
    
    <interactive>:3:1: error:
        Precedence parsing error
            cannot mix ‘+’ [infixl 6] and prefix `-' [infixl 6] in the same infix expression

    想要使用熟悉的负数必须这么用:“6+(-(1/3))”。这样做的原因在于,Haskell内应用函数的方法类似这样:“f 4”。那么如果出现“f -3”就会出现歧义:这个f到底是变量还是函数?这个-3是参数吗?类似的道理,如果输入“2*-3”同样会报错,因为编译器会把*-当作一个参数。这些和负数相关的东西需要我们记住。

    布尔值、比较操作符

    布尔值(True/False)不能同1与0直接等价,二者相比较会出现错误(相关内容见下报错信息)。逻辑与与逻辑或的操作符号分别为&&与||。Haskell里,逻辑操作符的参数必须为Bool型。
    各种比较操作符(comparison operator)返回bool值。Haskell里的不等于是/=,类似;其逻辑非的操作符是not而不是!。

    预设值与赋值

    一部分变量是有预设值的,如ππ,是可以直接通过pi来访问的。但是e不是。利用let语句我们可以给变量赋值。

    ghci> let e = exp 1

    注意,这里的exp是内嵌函数,而Haskell的特色就是调用函数不加括号。

    进一步了解

    实际上,在上面的探索过程中,至少笔者本人已经会遇到一些报错信息。这个时候可以去浏览网上的帮助文档来解决自己的疑难。Haskell给的报错信息是很有条理的,至少不会一个错爆出来十几个Error和四五十个Note。

    列表及其操作

    列表类似python的语法([1,2,3]),但是其内部成员类型应当一致。同样,我们可以利用类似pascal的语法来声明一个列表:

    ghci> [1..10]
    [1,2,3,4,5,6,7,8,9,10]

    ..表示枚举,它只适用于可枚举的对象,形成一个闭区间。比如说你对”angry”和”excited”枚举是无意义的。
    利用这种语法可以写出各种骚序列:

    ghci> [1.0,1.25..2.0]
    [1.0,1.25,1.5,1.75,2.0]
    ghci> [1,4..15]
    [1,4,7,10,13]
    ghci> [10,9..1]
    [10,9,8,7,6,5,4,3,2,1]

    给定的第一、第二项决定了公差(对于浮点数,请注意浮点数误差问题)。注意第二种情况,由于13+3=16>15,并没有把15/16给进去。

    列表间操作

    连接两个列表用++符号。在列表头加入一个元素用:符号。具体的示例见下:

    ghci> [] ++ [False,True] ++ [True]
    [False,True,True]
    ghci> 1:[5,5,1]
    [1,5,5,1]

    你可以试试[1,5,5]:1会发生什么,反正结果蛮气人的。

    字符(串)

    双引号规定字符串。接受转义字符。putStrLn输出一字符串。单引号规定字符。实际上,双引号和由单引号构成的列表似乎是等价的:

    ghci> let a = ['l', 'o', 't', 's', ' ', 'o', 'f', ' ', 'w', 'o', 'r', 'k']
    ghci> a
    "lots of work"
    ghci> a == "lots of work"
    True

    这样,适用于列表的操作应当亦适用于字符串。

    一个实际的程序

    -- file: WC.hs
    -- lines beginning with "--" are comments.
    
    main = interact wordCount
        where wordCount input = show (length (lines input)) ++ "
    "

    “–”如所见,两个连杠是注释的标志。将这段程序保存到WC.hs文件中,你想要处理的输入保存到一文件中,然后运行它(runghc WC < I_am_a_input.txt),它会计算输入的内容的行数。这段操作的原理后面会提及。

    如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
  • 相关阅读:
    DDD之3实体和值对象
    DDD之2领域概念
    DDD之1微服务设计为什么选择DDD
    SOFA入门
    COLA的扩展性使用和源码研究
    kafka可插拔增强如何实现?
    请设计一个核心功能稳定适合二开扩展的软件系统
    如何保证kafka消息不丢失
    kafka高吞吐量之消息压缩
    kafka消息分区机制原理
  • 原文地址:https://www.cnblogs.com/samhx/p/Haskell-1.html
Copyright © 2020-2023  润新知