Perl 6 程式設計教學:函數式程式設計 (Functional Programming)

PUBLISHED ON NOV 29, 2017 — PROGRAMMING

    函數式程式設計 (functional programming) 是一種程式設計的模範 (paradigm),主要見於 Lisp 和 ML 家族語言。由於函數式程式易於平行化處理,近年來許多主流語言也吸收了一些函數式程式的概念。一些大數據框架,像是 Hadoop 和 Spark 等,也用到函數式程式的概念。本文介紹以 Perl 6 撰寫函數式程式。

    比起傳統的指令式程式,函數式程式一開始比較難理解,如果讀者覺得過於困難,可以先略過這個章節。

    函式物件

    函數式程式的前提在於函式為第一級物件 (first-class object),簡單地說,函式可以做為值。由於函式可以做為值,函式可以做為其他函式的參數,也可以做為回傳值。

    以下是實例:

    或者是將現有的函式的參考傳入:

    也可以用以下較為簡略的寫法,算是一種語法糖:

    閉包

    閉包 (closure) 是一種帶有狀態的 (stateful) 副常式。以下是實例:

    以下例子使用閉包生成費伯那西數列:

    以下實例用閉包生成質數數列:

    以下例子將雜湊包在閉包中,做為簡易的快取:

    高階函式

    高階函式 (higher-order function) 是指使用函式做為參數或用函式做為回傳值的函式。我們先前的閉包也是一種高階函式。以下是一個以副常式為參數的實例:

    filter 副常式以一個陣列和一個副常式為參數,回傳符合該副常式的新陣列。

    由於 Perl 6 已經將一些常見的高階函式寫好,我們不需要每次都從頭撰寫,以下是一些例子:

    • grep:傳入串列,回傳符合特定條件的串列
    • map:將串列經轉換後,回傳新串列
    • reduce:將串列縮減為純量
    • sort:依照特定條件排列後回傳新串列
    • zip:將兩個串列組合,回傳新串列

    以下為實例:

    高階函數間可進一步組合,如下例:

    上例是將處理順序倒著寫,一開始會覺得較不易閱讀。也可以將其改為方法呼叫的方式,如下:

    迭代器

    Perl 6 提供 gathertake 的語法,可用來撰寫迭代器。gather 區塊內每次碰到 take 時,都會跳出該區塊,並取出一個值,下一次迭代時,會跳回原先的位置,繼續走迴圈。

    我們將先前的 filter 副常式改寫如下:

    這樣子看起來和先前的寫法沒啥差異,不過,迭代器有 laziness 的特性,如以下實例:

    由於 gather 區塊有 laziness 的特性,即使是無限長的串列,也是可以順利執行。如果用傳統的迴圈則會變成無窮迴圈,無法無法執行。

    以下例子用 gather 重寫質數數列,可用更簡潔的語法取質數:

    以下例子用 gather 區塊重寫費伯那西數列:

    由此可見,take 不一定要在 gather 區塊的最尾端,可使程式寫法更靈活。

    comments powered by Disqus