Simple Haskell: Prepare

Mac下搭建Haskell

Haskell Platform 是一个大包的Haskell开发环境,包含GHC已经一些三方库,已经包管理工具cabal,类似Python中的pip.
在Haskell官方直接下载即可,下载后按照提示进行安装.安装完成后配置程序路径:

vim ~/.bash_profile
# Setting PATH for Haskell
export PATH="$HOME/Library/Haskell/bin:$PATH"
:wq
source ~/.bash_profile
which ghc
/usr/local/bin/ghc
which ghci
/usr/local/bin/ghc
which cabal
/usr/local/bin/cabal
cabal update
cabal install ghc-mod
cabal info ghc-mod

然后开启Intellij IDEA,添加Haskell插件或HaskForce插件,重启IDEA,创建一个新的Haskell工程,此时需要设置ghc-mod和JDK路径,然后就可以使用IDEA进行开发了.

其中,ghc是生成本地代码的优化编译器,ghci是一个交互解释器和调试器,runghc是一个以脚本形式(不需要首先编译)运行Haskell程序.

在ghci中,命令行提示会随着加载的模块变化而变化,有时会变得很长影响输入,可以使用如下命令进行修改:

Prelude> :set prompt "ghci>"
ghci>

调用:module方法预加载一个模块:

ghci> :module + Data.Ratio

然后就可以使用Data.Ratio中的功能了,该模块提供一些有理数的计算.

运算符

可以吧ghci当做一个计算器使用:加(+),减(-),乘(*),除(/),乘方(^),同时支持使用前缀方式运算: (+) 2 2

布尔值使用True和False表示,(&&)表示逻辑与,(||)表示逻辑或,同时Haskell中并没有定义数字1等值于True,或者数字0等值于False.

Haskell中的等于比较分别为:==,>=,<=,/=,最后一个不等于并不是一般语言中常用的!=,而其常用的”非”则用 not 表示,True == not False

调用:info方法则可以查看各种操作的优先级,比如:

ghci> :info (+)
class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a
  ...
    -- Defined in GHC.Num
infixl 6 +

ghci> :info (*)
class (Eq a, Show a) => Num a where
  ...
  (*) :: a -> a -> a
  ...
    -- Defined in GHC.Num
infixl 7 *

这里的”infixl 6 +”表示”+”的优先级为6,”infixl 7 “表示”“的优先级为7,数字越大表示优先级越高.

ghci> :info (^)
(^) :: (Num a, Integral b) => a -> b -> a   -- Defined in GHC.Real
infixr 8 ^

乘方的优先级则为8,同时和上面的不同是,infixl与infixr,前者表示左结合,后者表示右结合.

列表

Haskell中的列表与Python类似,但是Haskell中的”,”作为分隔符,不能在右括号前多出一个逗号,同时列表中的元素类型必须相同.

ghci> [1,2,3]
[1,2,3]

如果使用列举符号(..)来表示一系列元素,Haskell则会自动对列举的内容进行填充,列举只能用于一些可列举的类型,字符串则不适合列举:

ghci> [1..10]
[1,2,3,4,5,6,7,8,9,10]
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]

如果没有填写结尾的话比如:[1..],这时会生成一个无穷列表而造成崩溃.

列表合并:

ghci> [3,1,3] ++ [3,7]
[3,1,3,3,7]
ghci> [] ++ [False,True] ++ [True]
[False,True,True]

添加元素:

ghci> 1 : [2,3]
[1,2,3]
ghci> 1 : []
[1]

字符串和字符

Haskell使用双引号表示一个字符串:

ghci> "This is a String."
"This is a String."

字符串的转义字符基本与其他语言一致:

ghci> putStrLn "Here's a newline -->\n<-- See?"
Here's a newline -->
<-- See?

单字符使用单引号表示:

ghci> 'a'
'a'

字符串实质上一一个单字符的列表:

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

“”表示空字符串,与[]同义.

同样可以使用列表方法操作字符串:

ghci> 'a':"bc"
"abc"
ghci> "foo" ++ "bar"
"foobar"

类型

Haskell中所有的类型都是以大写字符开头,所有变量名都是以小写字母开头.

修改ghci,让它在返回表达式求值时同时返回打印结果的类型,使用ghci的:set命令:

Prelude> :set +t

Prelude> 'c'    -- 输入表达式
'c'             -- 输出值
it :: Char      -- 输出值的类型

Prelude> "foo"
"foo"
it :: [Char]

上面结果中显示的”it:”是一个特殊标量,表示最后一次求值结果的变量名,只是ghci的一个辅助功能.x :: y 表示表达式 x 的类型为 y.而[char]表示的就是String.

Haskell的整数表示为Integer,其长度仅受限于操作系统的内存大小.

分数使用%构建,分子在左边,分母在右边:

Prelude> :m +Data.Ratio        // :m 为 :module的缩写
Prelude Data.Ratio> 11 % 29
11 % 29
it :: Ratio Integer            // 表示类型为: 由整数构成的分数

使用 :unset +t 命令取消对类型的打印,而使用 :type a 命令可以显式的打印变量a的类型

行计数程序

使用Haskell编写一个行计数程序:

-- file: ch01/WC.hs
-- lines beginning with "--" are comments.

main = interact wordCount
    where wordCount input = show (length (lines input)) ++ "\n"

再创建一个 quux.txt,包含以下内容:

Teignmouth, England
Paris, France
Ulm, Germany
Auxerre, France
Brunswick, Germany
Beaumont-en-Auge, France
Ryazan, Russia

然后在shell下执行:

$ runghc WC < quux.txt
7

得到结果为7行.