從Java和Haskell一些程式碼對比中認識函數語言程式設計 - morgenthum.dev
很多朋友和同事問我為什麼談論Haskell。在我學習Haskell之前,我總是使用Java,C和C ++等主流語言 - 並且仍然喜歡它們。那麼一個命令式的開發人員怎麼會變成Haskell粉絲?在本文中,我想解釋一下 - 特別是對於函式程式設計經驗較少的開發人員。
控制流
控制流程描述瞭如何告訴程式要做什麼 - 制定演算法。有三個基本控制元素:
- 序列 - 按順序執行程式碼
- 重複 - 重複執行程式碼
- 條件 - 按條件將程式碼拆分為分支
物件導向程式設計:
- 序列是使用逐行逐句的語句實現
- 重複是使用迴圈實現,如for或while語句或遞迴
- 條件是使用if ... else或switch陳述
這是一個使用Java的簡單示例,它以文字為中心。文字作為字串陣列傳遞。每一行都是該陣列的一個元素:
void alignCenter(String[] text) { int maxLength = 0; for (String line : text) { if (line.length() > maxLength) { maxLength = line.length(); } } for (int i = 0; i < text.length; ++i) { int spaceCount = (maxLength - text[i].length()) / 2; StringBuilder builder = new StringBuilder(); for (int j = 0; j < spaceCount; ++j) { builder.append(' '); } builder.append(text[i]); text[i] = builder.toString(); } } |
函數語言程式設計
- 序列是使用一鏈串的呼叫實現chained calls
- 重複是使用遞迴實現
- 條件是使用模式匹配實現,如case ... of或if ... else表示式
下面是Haskell中的相同示例,它顯示了模式匹配和遞迴的用法:
alignCenter :: [String] -> [String] alignCenter xs = alignCenter' maxLength xs where maxLength = maximum (map length xs) alignCenter' :: Int -> [String] -> [String] alignCenter' _ [] = [] alignCenter' n (x:xs) = (replicate spaceCount ' ' ++ x) : alignCenter' n xs where spaceCount = div (n - length x) 2 |
下面是一個簡短的版本,透過使用map和lambda函式避免遞迴:
alignCenter :: [String] -> [String] alignCenter xs = map (\x -> replicate (div (n - length x) 2) ' ' ++ x) xs where n = maximum (map length xs) |
函式的第一行是函式簽名:
alignCenter :: [String] -> [String]
這告訴我們,我們有一個名為alignCenter的函式,它將一個字串列表作為輸入,並返回一個新的字串列表作為輸出(從左到右理解)。
然後第二行程式碼中是函式體的內容,第一個函式確定字串列表中的最長行並呼叫第二個函式。我們透過一個簡單的表示式maximum (map length xs)終止了我們的oop程式碼的第一個迴圈。
那麼它是怎樣工作的?我們來看看所有相關maximum (map length xs)函式的簽名:
length :: [a] -> Int map :: (a -> b) -> [a] -> [b] maximum :: [a] -> a |
length函式獲取任何型別的列表並返回一個Int。所有小寫型別的型別簽名是型別變數,類似於在List<T>Java中的型別T。
map函式需要獲取兩個輸入引數:第一個是型別a -> b;第二個獲取[a]並返回。
那麼它是什麼意思“它需要一個函式作為引數”?對,是真的!您可以將函式作為引數傳遞,既不像C中那樣的函式指標也不像Java中那樣引用方法引用 - 實際函式作為第一類值。
將函式作為引數使用或將新函式作為結果返回的函式稱為高階函式。那麼這個功能有什麼作用呢?它將傳遞[a]中每個元素給a -> b函式,在這個函式中,將a轉為b,並且收集collect形成一個新的list
現在讓我們解決型別變數map length xs,其中xs的型別為[String]:
map :: (String -> Int) -> [String] -> [Int] |
您需要知道這String是一個型別的同義詞[Char],表示字元列表。這就是為什麼它與length函式相容的原因。表示式map length ["Hello", "World!"]將解析為[5, 6]。(計算這兩個字串的長度),我們感興趣的是列表裡面最長的字串的長度,所以我們傳遞給結果列表maximum返回列表,這是最大的數字6。
更多介紹點選標題見原文。
相關文章
- Haskell學習-函數語言程式設計初探Haskell函數程式設計
- 函數語言程式設計(一) 認識“程式設計正規化”和“函式”函數程式設計函式
- Java函數語言程式設計知識分享!Java函數程式設計
- Java 函數語言程式設計Java函數程式設計
- 重識Java8函數語言程式設計Java函數程式設計
- Java 函數語言程式設計(一)初識篇Java函數程式設計
- Java 中的資料流和函數語言程式設計Java函數程式設計
- 從函數語言程式設計說起函數程式設計
- 從 Redux 原始碼談談函數語言程式設計Redux原始碼函數程式設計
- 《Java 8函數語言程式設計》選讀:為什麼要給Java 8中加入函數語言程式設計?Java函數程式設計
- 筆記:Haskell函數語言程式設計入門 - 惰性求值簡介筆記Haskell函數程式設計
- 函數語言程式設計函數程式設計
- 程式程式碼進化的一些思考:從物件導向到設計模式,到函數語言程式設計物件設計模式函數程式設計
- JavaScript中的函數語言程式設計JavaScript函數程式設計
- JavaScript 中的函數語言程式設計JavaScript函數程式設計
- Java中的函數語言程式設計(八)流Stream並行程式設計Java函數程式設計並行行程
- Scala 函數語言程式設計(一) 什麼是函數語言程式設計?函數程式設計
- 我對函數語言程式設計的理解函數程式設計
- 對函數語言程式設計的誤解函數程式設計
- Java 函數語言程式設計的前生今世Java函數程式設計
- Java 函數語言程式設計(三)流(Stream)Java函數程式設計
- Java8的函數語言程式設計Java函數程式設計
- Java中的函數語言程式設計(三)lambda表示式Java函數程式設計
- Java中函數語言程式設計Monad概念介紹Java函數程式設計
- 函數語言程式設計,真香函數程式設計
- javascript函數語言程式設計JavaScript函數程式設計
- 初探函數語言程式設計函數程式設計
- 函數語言程式設計初探函數程式設計
- JavaScript 函數語言程式設計JavaScript函數程式設計
- Js中函數語言程式設計的理解JS函數程式設計
- Python 中的函數語言程式設計Python函數程式設計
- 函數語言程式設計中的常用技巧函數程式設計
- 從函數語言程式設計到Ramda函式庫(一)函數程式設計函式
- 函式式思維和函數語言程式設計函式函數程式設計
- Java技術分享之函數語言程式設計!Java函數程式設計
- Java技術分享之函數語言程式設計Java函數程式設計
- 淺談函數語言程式設計與 Java Stream函數程式設計Java
- Java 函數語言程式設計(二)Lambda表示式Java函數程式設計