灰暗已經(jīng)過去,又開始寫文章啦啦啦!??!
1, 之前學(xué)習(xí)大數(shù)據(jù)要用到scala語(yǔ)言,遇到scala里面的函數(shù)式部分有點(diǎn)懵逼。后來就想深入學(xué)習(xí)一下函數(shù)式語(yǔ)言。現(xiàn)在的很多命令式語(yǔ)言都支持函數(shù)式風(fēng)格,但是因?yàn)槊钍降乃枷敫畹俟潭嗄旰芏嗪瘮?shù)式的思想很難理解。于是就想直接從一門純粹的函數(shù)式語(yǔ)言入手從零開始學(xué)習(xí)函數(shù)式編程思想。去年在工作空閑時(shí)花過一段時(shí)間學(xué)習(xí)haskell,當(dāng)時(shí)有點(diǎn)暈,很多東西沒搞明白,后來事情太多中斷了。如今有空了,再繼續(xù)吧。
本文先從Haskell Cookbook上的求解一元二次方程開始吧,熟悉一下語(yǔ)法。
2, 配置環(huán)境:按照haskell文檔安裝stack,別用brew install stack,版本太舊,問題多多。
haskell官方IDE是基于eclipse的,不太好用,目前直接使用vs code。
3, stack new hello新建工程。

項(xiàng)目結(jié)構(gòu).png
-- Quadratic.hs
module Quadratic where
-- 導(dǎo)入模塊
import Data.Complex
-- 定義數(shù)據(jù)類型:record格式
-- =號(hào)左邊叫類型構(gòu)造,可以接受類型參數(shù),相當(dāng)于定義泛形類型
-- =號(hào)右邊叫數(shù)據(jù)構(gòu)造,有兩個(gè)參數(shù)時(shí)數(shù)據(jù)構(gòu)造名稱可以放中間,數(shù)據(jù)構(gòu)造按是否指定字段名分兩種格式
-- record格式每個(gè)字段名自身是一個(gè)函數(shù) 類型為 數(shù)據(jù)構(gòu)造 -> 字段類型,所以訪問對(duì)象字段的格式:(字段名 對(duì)象名)
data Quadratic = Quadratic {a :: Double, b :: Double, c :: Double}
deriving Show
-- 定義類型別名 相當(dāng)于c++中的 typedef/using
type RootT = Complex Double
-- 定義數(shù)據(jù)類型:只指明字段類型,沒有字段名稱
data Roots = Roots RootT RootT
deriving Show
-- 定義函數(shù)頭
roots :: Quadratic -> Roots
-- 定義函數(shù)體
-- 模式匹配 _表示忽略具體值 error拋異常
roots (Quadratic 0 0 _) = error "不是一元二次方程"
-- let <bindings> in expression
roots (Quadratic 0.0 b c) = let root = ((-c) / b :+ 0)
in Roots root root
roots (Quadratic a b c) = let discriminant = b * b - 4 * a * c
in rootsInternal (Quadratic a b c) discriminant
rootsInternal :: Quadratic -> Double -> Roots
-- |之后表示模式匹配的條件,滿足條件才能匹配上然后執(zhí)行對(duì)應(yīng)的邏輯
-- 同一個(gè)語(yǔ)句塊必須左對(duì)齊
rootsInternal q d | d == 0 = let r = (-(b q) / 2.0 / (a q))
root = r :+ 0
in Roots root root
-- expression where <bindings>
rootsInternal q d | d < 0 = Roots (realpart :+ complexpart) (realpart :+ (-complexpart))
where plusd = -d
twoa = 2.0 * (a q)
complexpart = (sqrt plusd) / twoa
realpart = - (b q) / twoa
rootsInternal q d | d < 0 = Roots (root1 :+ 0) (root2 :+ 0)
where plusd = -d
twoa = 2.0 * (a q)
dpart = (sqrt plusd) / twoa
prefix = -(b q) / twoa
root1 = prefix + dpart
root2 = prefix - dpart
-- Main.hs
module Main where
import Quadratic
import Data.Complex
str2double :: String -> Double
str2double str = read str :: Double
main :: IO ()
main = do
print "input a"
a <- getLine
print "input b"
b <- getLine
print "input c"
c <- getLine
-- $ 函數(shù)調(diào)用順序從右往左
putStrLn $ show $ roots (Quadratic (str2double a) (str2double b) (str2double c))
4, 編譯執(zhí)行
stack build
stack exec -- hello-exe

exec.png
5, 語(yǔ)法非常的神奇,去年一直搞不懂,現(xiàn)在再看有點(diǎn)明白了(可能是內(nèi)力更深了,哈哈哈)。
6, haskell采用縮進(jìn)語(yǔ)法,但是沒有python那么嚴(yán)格,只要求同一個(gè)語(yǔ)句塊左邊對(duì)齊(???)。