在过去的几个月里,学习Haskell让我以为很是快乐,可是入门的过程并无我原先想象的那么简单。我很是幸运地在一个正确的地方工做,而且所以可以在Facebook参加Bryan O'Sullivan的Haskell课程。在Try Haskell上玩了一段时间后,最终你就会想要在本身的电脑上安装GHC了。html
Cabal是Haskell用于构建应用程序和库的公共架构。和其配套使用的工具包是Hackage,做用则相似于Perl的CPAN,Python的pip或者Ruby的gem。你可能对其表示失望,可是它也不至于糟糕。node
当最终安装完cabal包时,默认会把它安装到 ~/.cabal/
目录,脚本则安装到 ~/.cabal/bin目录下。紧接着,还要添加环境路径。如下设置便可知足,但也能够按照你本身喜爱来设置shell的profile: ios
echo 'export PATH=$HOME/.cabal/bin:$PATH'>> ~/.bashrc
在使用cabal工做以前,你还须要更新可用包列表。这只是偶尔是使用到而已,特别在安装或者更新新的包时。git
cabal update
这时,~/.cabal/config 文件的library-profiling 选项还没开启。若是你如今不开启,之后再开启则可能须要从新编译全部的文件。开启此选项,须要编辑~/.cabal/config文件,而且设置--library-profiling: Falsetolibrary-profiling: True。github
$forfin ~/.cabal/config; do cp $f $f.old && sed-E's/(-- )?(library-profiling: )False/\2True/'< $f.old > $f; done
在安装其余东西前,还须要安装 Calbal installer:shell
cabal install cabal-install
ghc-mod是在Emacs和Vim中集成GHC的环境.你也许可以从SublimeHaskell中使用Sublime
Text2和ghc-mod.我至今只试过在Emacs中使用过它.Vim用户能够尝试hdevtools,它编译更加迅速而且一样准确(参考kamatsu's comment).编程
$ cabal install ghc-mod
显然你必须为你的Emacs配置它,而且我会将我如今的 ~/.emacs.d留给你作参考.segmentfault
Cabal-dev是一个能帮助你安装Haskell软件的工具。它相似于Python 的 virtualenv或者Ruby的rvm,可是使用上有些不一样。Cabal-dev 能让你免于“Calbal Hell”(即你如今安装的包和你以前安装的包存在依赖冲突)的烦恼。bash
尽可能使用calbal-dev 代替仅仅使用cabal进行编译工做。其主要代价是花费多一点时间编译那些已经安装在某处的包(和浪费一些磁盘空间),不过这也是至关划算的了。markdown
使用源码编译和安装Cabal-dev:
若是你想尝试一些工具,可是并不想污染你的haskell环境,你可使用cabal-dev。cabal-dev默认的沙盒在 ./cabal-dev,可是你能够把它放到任何地方。下面的例子中, 我将安装 darcs 2.8.2 (一个haskell写的版本控制系统)到/usr/local/Cellar/darcs/2.8.2中,并使用Homebrew建立符号连接。在其余平台你可能但愿使用本身指定的路径和PATH环境变量。
$ cabal-dev install -s /usr/local/Cellar/darcs/2.8.2 darcs-2.8.2 $ brew link --overwrite darcs
OK!如今darcs已经在你的PATH中了,并且你并不须要担忧版本冲突。好吧,你没办法彻底摆脱它们,可是没有之前那么多了。特别注意,cabal-dev会将全部包安装在沙盒顶层目录。这意味着若是两个包有着相同的依赖关系(彻底相同),它们会互相破坏它们内部指向依赖的包内的文件的符号连接,例如发布协议文件和文档。这样使用--overwrite可能没有什么损失,可是你最好先用--overwrite --dry-run选项检查一番。有些麻烦,可是不会毁掉你一成天的成果。
若是你想看看你所安装的darcs的版本,使用cabal info darcs。
其余有意思的haskell写的工具(不分前后):
GHCi是GHC交互式解释器的缩写。更详细的文档请参考GHC用户指南(第二章:使用GHCi)。你将在编码过程当中花上很长一段时间,你大概想要设置一个更短的提示符。它刚开始的时候看起来像这样:
Prelude>
一旦你开始引入模块,提示符将不断变长。真的,你一辈子都不须要这么长的提示符。
Prelude>:m+Data.List Prelude Data.List>:m+Data.Maybe Prelude Data.List Data.Maybe>
配置文件是.ghci。我用一个很是简单的ASC II提示符,而另外一些人喜欢把提示符设置成诸如"λ>"这样。
echo':set prompt "h> "'>> ~/.ghci
Hello World:
$ ghci h>putStrLn"Hello World!" Hello World! h>
官方对Hackage支持还很不足,但其也有非官方镜像.
使人遗憾的是,目前Hackage还不是很稳定。我不知道什么缘由形成的,但但愿他们能尽早作点什么。Hackage有其工做区,你可使用hdiff.luite.com或者hackage.csc.stanford.edu的仓库。
修改 ~/.cabal/config 文件行为:
remote-repo: hackage.haskell.org: http://hackage.haskell.org/packages/archive
变成这样:
-- TODO When hackage is back up, set back to hackage.haskell.org! -- remote-repo: hackage.haskell.org: http://hackage.haskell.org/packages/archive remote-repo: hdiff.luite.com: http://hdiff.luite.com/packages/archive -- remote-repo: hackage.csc.stanford.edu: http://hackage.scs.stanford.edu/packages/archive
当你完成修改远程仓库的设置后,你将须要更新包列表:
cabal update
不要忘记后续把它还原回来!
你最终会明白如何去作,可是一个快速的方法是直接使用cabal-dev。下面告诉你开始一个简单的程序。
对于你本身的项目,你可能想要去掉-n标志,让cabal-dev询问你你想要的选项。-n会使用全部默认的选项而没有提示。
$ mkdir -p ~/src/hs-hello-world $ cd ~/src/hs-hello-world $ touch LICENSE $ cabal init -n --is-executable
这回生成一个Setup.hs文件和hs-hello-world.cabal文件。下面须要修改main-is这行来讲明你要从哪一个文件编译你的可执行文件。最终的文件可能像这样。
hs-hello-world.cabal
-- Initial hs-hello-world.cabal generated by cabal init. For further -- documentation, see http://haskell.org/cabal/users-guide/ name: hs-hello-world version: 0.1.0.0 -- synopsis: -- description: license: AllRightsReserved license-file: LICENSE -- author: -- maintainer: -- copyright: -- category: build-type: Simple cabal-version: >=1.8 executable hs-hello-world main-is: HelloWorld.hs -- other-modules: build-depends: base ==4.5.*
而后建立一个HelloWorld.hs,可能像这样:
main :: IO() main = putStrLn "Hello, world!"
你能够编译并安装它到一个本地的沙盒:
$ cabal-dev install Resolving dependencies... Configuring hs-hello-world-0.1.0.0... Building hs-hello-world-0.1.0.0... Preprocessing executable'hs-hello-world'forhs-hello-world-0.1.0.0... Installing executable(s)in/Users/bob/src/hs-hello-world/cabal-dev//bin Installed hs-hello-world-0.1.0.0 $ ./cabal-dev/bin/hs-hello-world Hello, world!
生成的文件比较大,由于他是静态链接的。你能够复制它到任何处理器架构和操做系统相同的机器上,它能够直接运行。
你能够跳过安装步骤,这样可能节省一点时间:
$ cabal-dev configure Resolving dependencies... Configuring hs-hello-world-0.1.0.0... $ cabal-dev build Building hs-hello-world-0.1.0.0... Preprocessing executable'hs-hello-world'forhs-hello-world-0.1.0.0... [1 of 1] Compiling Main ( HelloWorld.hs, dist/build/hs-hello-world/hs-hello-world-tmp/Main.o ) Linking dist/build/hs-hello-world/hs-hello-world... $ ./dist/build/hs-hello-world/hs-hello-world Hello, world!
既然这个项目没有什么依赖,你可跳过一些步骤。
能够解释执行它,不须要编译:
$ runghc HelloWorld.hs Hello, world! $ ghci GHCi, version7.4.2: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim...linking...done. Loading package integer-gmp...linking...done. Loading package base...linking...done. Prelude>:load HelloWorld [1of1] Compiling Main ( HelloWorld.hs, interpreted ) Ok, modules loaded: Main. *Main>main Hello, world!
你甚至不须要用cabal-dev(cabal)编译它:
$ runghc Setup.hs configure Configuring hs-hello-world-0.1.0.0... $ runghc Setup.hs build Building hs-hello-world-0.1.0.0... Preprocessing executable'hs-hello-world'forhs-hello-world-0.1.0.0... [1 of 1] Compiling Main ( HelloWorld.hs, dist/build/hs-hello-world/hs-hello-world-tmp/Main.o ) Linking dist/build/hs-hello-world/hs-hello-world...
可是对一些复杂的项目,你可使用cabal-dev ghci(在cabal-dev configure &&
cabal-dev build以后)。注意它会自动装载你的可执行文件到解释器里:
$ cabal-dev ghci on the commandline: Warning:-O conflicts with--interactive;-O ignored. GHCi, version7.4.2: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim...linking...done. Loading package integer-gmp...linking...done. Loading package base...linking...done. Ok, modules loaded: Main. h> main Hello, world!
更多你想知道的GHCi用法能够在Chapter 2. Using GHCi找到。
λ >> :t main main :: IO () λ >> :t map map :: (a -> b) -> [a] -> [b] λ >> :t map (+1) map (+1) :: Num b => [b] -> [b]
:i 显示一个符号的信息(函数,typeclass,类型等等)
λ >> :i Num class Num a where (+) :: a -> a -> a (*) :: a -> a -> a (-) :: a -> a -> a negate :: a -> a abs :: a -> a signum :: a -> a fromInteger :: Integer -> a -- Defined in `GHC.Num' instance Num Integer -- Defined in `GHC.Num' instance Num Int -- Defined in `GHC.Num' instance Num Float -- Defined in `GHC.Float' instance Num Double -- Defined in `GHC.Float' λ >> :info map map :: (a -> b) -> [a] -> [b] -- Defined in `GHC.Base' λ >> :info Int data Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types' instance Bounded Int -- Defined in `GHC.Enum' instance Enum Int -- Defined in `GHC.Enum' instance Eq Int -- Defined in `GHC.Classes' instance Integral Int -- Defined in `GHC.Real' instance Num Int -- Defined in `GHC.Num' instance Ord Int -- Defined in `GHC.Classes' instance Read Int -- Defined in `GHC.Read' instance Real Int -- Defined in `GHC.Real' instance Show Int -- Defined in `GHC.Show'
:m 增长一个模块
λ >> :m +Data.List λ >> sort [10, 9..1] [1,2,3,4,5,6,7,8,9,10]
:l 导入一个模块,:r 从新导入模块
λ >> :! echo 'hello = print "hello"' > Hello.hs λ >> :l Hello [1 of 1] Compiling Main ( Hello.hs, interpreted ) Ok, modules loaded: Main. λ >> hello "hello" λ >> :! echo 'hello = print "HELLO"' > Hello.hs λ >> :r [1 of 1] Compiling Main ( Hello.hs, interpreted ) Ok, modules loaded: Main. λ >> hello "HELLO"
我学习Haskell时发现有些资料很是有用
我发现这本书是一个很好的起点,我推荐你先读完它。他并非很是深刻让你了彻底解GHC如何工做,可是我发现看完这本书以后读写Haskell代码会比较适应。
这本书比较权威,可是仍然对初学者比较友好。他会教你比较真实的Haskell开发,例如写测试,配置,IO及并发等等。
我把我所说的基于建议。若是我漏掉了什么重要的,请告诉我!我没有试图介绍一切,我认为haskell wiki在这方面作得比我好。这些就是要注意的了。
原文 Getting Started with Haskell
翻译 crab2313, suzhaoda, ShaoFantasy, 梁洛克, HeliosM
修订 SegmentFault