亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

優(yōu)化函數(shù)式編程:向 PHP 移植 Clojure 函數(shù)

MarvinZhang / 2596人閱讀

摘要:不論你想要成熟的面向?qū)ο蟮某绦蛟O(shè)計,還是程序式或函數(shù)式編程,都可以做到。但我們不禁要問,擅長函數(shù)式編程嗎本文系國內(nèi)管理平臺工程師編譯整理。在函數(shù)式編程中,目標(biāo)之一是減輕副作用。

許多通用程序設(shè)計語言試圖兼容大多數(shù)編程范式,PHP 就屬于其中之一。不論你想要成熟的面向?qū)ο蟮某绦蛟O(shè)計,還是程序式或函數(shù)式編程,PHP 都可以做到。但我們不禁要問,PHP 擅長函數(shù)式編程嗎?本文系國內(nèi) ITOM 管理平臺 OneAPM 工程師編譯整理。

筆者在今年冬天開始時,在 Recurse Center致力于學(xué)習(xí) Clojure,更加深入地了解了函數(shù)式編程,并重新拾起 PHP 的客戶端工作。但筆者仍然希望運用一些高階函數(shù)和概念,并對它們進行研究。

筆者已經(jīng)在 PHP 中實施了模擬 LISP 語言,并看到了一些在 PHP 中通過使用 underscore 類庫以兼容某些關(guān)鍵函數(shù)方法的嘗試。但為了使 Clojure 在寫入其它編程語言時仍然保有較高的速度,筆者特意鏡像 Clojure 的標(biāo)準(zhǔn)庫,以使自己能在編寫真正的 PHP 代碼時,以 Clojure 的方式思考。雖然在學(xué)習(xí)的過程中繞了一些彎路,筆者仍然愿意向各位展示自己是如何實現(xiàn) interleave 函數(shù)的。

幸運地是,已經(jīng)有人執(zhí)行了 array_some 和 array_every,并且非常地道(至少筆者這么認(rèn)為)。

/**
 * Returns true if the given predicate is true for all elements.
 * credit: array_every and array_some.php
 * https://gist.github.com/kid-icarus/8661319
 */
function every(callable $callback, array $arr) {
  foreach ($arr as $element) {
    if (!$callback($element)) {
      return FALSE;
    }
  }
  return TRUE;
}

/**
 * Returns true if the given predicate is true for at least one element.
 * credit: array_every and array_some.php
 * https://gist.github.com/kid-icarus/8661319
 */
function some(callable $callback, array $arr) {
  foreach ($arr as $element) {
    if ($callback($element)) {
      return TRUE;
    }
  }
  return FALSE;
}

我們只要簡單地取消調(diào)用 every 函數(shù),就可以運用 not-every 函數(shù)插入一些容易實現(xiàn)的目標(biāo),同時仍然有相同 signature。

/**
 * Returns true if the given predicate is not true for all elements.
 */
function not_every(callable $callback, array $arr) {
    return !every($callable, $arr);
}

如你所見,筆者已經(jīng)去掉了前綴 array_。PHP 的不便之處在于強調(diào)序函數(shù),通常使用前綴 array_ 來運行數(shù)列。筆者將此理解為這兩種函數(shù)的作者是在相互模仿。雖然數(shù)列在 PHP 中已經(jīng)形成事實數(shù)據(jù)結(jié)構(gòu),但標(biāo)準(zhǔn)數(shù)據(jù)庫以此種方式被寫入并不常見。

這一標(biāo)準(zhǔn)適用于基本高階函數(shù),你可以使用 array_map、array_reduce和 array_filter 結(jié)尾,而不是 map,recude 和 filter。如果這些還不夠,那參數(shù)便不一致了。array_reduce 和 array_filter 都以數(shù)列為第一個參數(shù),然后以回調(diào)值作為第二個參數(shù),首先調(diào)回 array_map。在 Clojure 中,通常首先運行回調(diào)函數(shù),所以讓我們將這些函數(shù)重新命名,然后只需一步就能使這些簽名變得正常:

/**
 * Applies callable to each item in array, return new array.
 */
function map(callable $callback, array $arr) {
    return array_map($callback, $arr);
}

/**
 * Return a new array with elements for which predicate returns true.
 */
function filter(callable $callback, array $arr, $flag=0) {
    return array_filter($arr, $callback, $flag);
}

/**
 * Iteratively reduce the array to a single value using a callback function
 */
function reduce(callable $callback, array $arr, $initial=NULL) {
    return array_reduce($arr, $callback, $initial);
}

我們目前沒有其它方法,所以當(dāng) Clojure 中的 reduce 函數(shù)通過了初始值并作為第二個參數(shù)時,它便有了另一個簽名。鑒于此,我們從現(xiàn)在開始就將 initial 作為最終值——畢竟相對于原函數(shù)來說,這仍然是一大進步。另外,我們也將在過濾函數(shù)中保留 $flag,它決定了是否全部通過鍵和值,還是只通過鍵。

在 Clojure 中,first 和 last 是十分有用的兩個函數(shù),相當(dāng)于 PHP 中的 array_shift 和 array_pop。它們的關(guān)鍵不同之處在于:PHP 中兩個命令具有毀壞性。以 array_shift 為例,它返回數(shù)列的第一項,同時又從原始數(shù)列中移除該項(當(dāng)數(shù)列被引用通過時)。在函數(shù)式編程中,目標(biāo)之一是減輕副作用。所以在后臺用 first 和 last 函數(shù)將數(shù)列復(fù)制一份,這樣原始數(shù)列就永遠不會被更改了。與之相對應(yīng)的是 rest 和 but-last 函數(shù),我們可以繼續(xù)使用 array_slice 來返回該部分。

/**
 * Returns the first item in an array.
 */
function first(array $arr) {
    $copy = array_slice($arr, 0, 1, true);
    return array_shift($copy);
}

/**
 * Returns the last item in an array.
 */
function last(array $arr) {
    $copy = array_slice($arr, 0, NULL, true);
    return array_pop($copy);
}

/**
 * Returns all but the first item in an array.
 */
function rest(array $arr) {
    return array_slice($arr, 1, NULL, true);
}

/**
 * Returns all but the last item in an array.
 */
function but_last(array $arr) {
    return array_slice($arr, 0, -1, true);
}

當(dāng)然,這些都只是低階函數(shù),可能看起來并不那么讓人興奮,但它們遲早會有用。順便問一下,大家知道 PHP 中與這些函數(shù)相對應(yīng)的「應(yīng)用」( https://en.wikipedia.org/wiki/Apply)嗎?答案可能是否定的。因為它們的名字十分深奧,不像其它編程語言中那些概念相同但名稱普通的命令。讓我們繼續(xù)將 call_user_func_array 替換為 apply 函數(shù)吧。

/**
 * Alias call_user_func_array to apply.
 */
function apply(callable $callback, array $args) {
    return call_user_func_array($callback, $args);
}

這太讓人興奮了!當(dāng)我們將函數(shù)名稱變得地道,并創(chuàng)建出低級別的抽象名稱,便有了一個能幫助我們創(chuàng)建更多有趣名稱的平臺。讓我們用 apply 幫助我們創(chuàng)建 complement:

function complement(callable $f) {
    return function() use ($f) {
        $args = func_get_args();
        return !apply($f, $args);
    };
}

這里使用了 func_get_args()函數(shù),當(dāng)所有值通過原始函數(shù)時,它就能夠抓取一個數(shù)列,這一數(shù)列中所有的值都按照它們通過時的順序排列。我們繼續(xù)返回匿名函數(shù),該函數(shù)能通過 use 獲取原始函數(shù) $f(因為所有的函數(shù)在PHP中都有新的域),然后在 $args 中調(diào)用 apply。

太好了,現(xiàn)在我們有了 complement 函數(shù),它能讓我們更加容易地實施與filter 函數(shù)相反的 remove 函數(shù)。通過返回回調(diào)的 complement 傳遞給filter,當(dāng)所有數(shù)據(jù)與預(yù)設(shè)條件不相符時,返回所有數(shù)據(jù)。

/**
 * Return a new array with elements for which predicate returns false.
 */
function remove(callable $callback, array $arr, $flag=0) {
    return filter(complement($callback), $arr, $flag);
}

換個角度來說,array_merge 和 contact 是等效的。下面以 Cons 和 conj 為例,在 Clojure 中,它們是向集合的開始或末尾增加項的標(biāo)準(zhǔn)方式,

/**
 * Alias array_merge to concat.
 */
function concat() {
    $arrs = func_get_args();
    return apply("array_merge", $arrs);
}

/**
 * cons(truct)
 * Returns a new array where x is the first element and $arr is the rest.
 */
function cons($x, array $arr) {
    return concat(array($x), $arr);
}

/**
 * conj(oin)
 * Returns a new arr with the xs added.
 * @param $arr
 * @param & xs add"l args to be added to $arr.
 */
function conj() {
    $args = func_get_args();
    $arr  = first($args);
    return concat($arr, rest($args));
}

例如,現(xiàn)在調(diào)用這兩個函數(shù),會生成相同的結(jié)果:

cons(1, array(2, 3, 4));
conj(array(1), 2, 3, 4);

這些低階工具足以讓 interleave 的書寫變得十分簡單。首先,我們使用func_get_args,取代在函數(shù)簽名中使用聲明參數(shù),這樣便能采用大量的數(shù)列作為函數(shù)參數(shù)。然后,我們將每個數(shù)列的第一項提出來組成一個新的數(shù)列,余下的每個數(shù)列作為每一個新數(shù)列。接著,檢查每個數(shù)列是否都保留有元素,再使用 concat 函數(shù)連接交錯數(shù)列的結(jié)果,如此反復(fù)。以可讀的實施以及與 Clojure 版本幾乎無差別的函數(shù)結(jié)果為結(jié)束,得到的結(jié)果就是證明 Clojure 生成了惰性序列。

/**
 * Returns a sequence of the first item in each collection then the second, etc.
 */
function interleave() {
    $arrs = func_get_args();
    $firsts = map("first", $arrs);
    $rests  = map("rest", $arrs);
    if (every(function($a) { return !empty($a); }, $rests)) {
        return concat($firsts, apply("interleave", $rests));
    }
    return $firsts;
}

因此,當(dāng)我們調(diào)用長度可變的數(shù)列來制作函數(shù)時:

interleave([1, 2, 3, 4], ["a", "b", "c", "d", "e"], ["w", "x", "y", "z"])

插入所有三個數(shù)列減去多余項,以其作為結(jié)果數(shù)列并以此結(jié)尾:

array (
    0 => 1,
    1 => "a",
    2 => "w",
    3 => 2,
    4 => "b",
    5 => "x",
    6 => 3,
    7 => "c",
    8 => "y",
    9 => 4,
    10 => "d",
    11 => "z",
)

當(dāng)然,Clojure 有非常棒的功能性,在這里我們并沒有提到,例如 interleave,它是返回惰性序列,而不是靜態(tài)采集。此外,由于數(shù)列會像 PHP 中的映射一樣加倍,那些類似于 assoc 的模擬方法就變得模棱兩可。如果大家對這些感興趣,并且想在下一個項目中使用它們,這些代碼已放到 GitHub 上供您閱讀參考。

cljphp on GitHub

原文地址:http://blackwood.io/porting-clojure-php-better-functional-programming/

本文系 OneAPM 工程師編譯整理。OneAPM 是應(yīng)用性能管理領(lǐng)域的新興領(lǐng)軍企業(yè),能幫助企業(yè)用戶和開發(fā)者輕松實現(xiàn):緩慢的程序代碼和 SQL 語句的實時抓取。想閱讀更多技術(shù)文章,請訪問 OneAPM 官方博客。

本文轉(zhuǎn)自 OneAPM 官方博客

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/21375.html

相關(guān)文章

  • JVM 平臺上的各種語言的開發(fā)指南[z]

    摘要:我們的目標(biāo)是建立對每一種語言的認(rèn)識,它們是如何進化的,未來將走向何方。有點的味道是堅持使用動態(tài)類型,但唯一還收到合理擁泵的編程語言,然而一些在企業(yè)的大型團隊中工作的開發(fā)者擇認(rèn)為這會是的一個缺陷。 為什么我們需要如此多的JVM語言? 在2013年你可以有50中JVM語言的選擇來用于你的下一個項目。盡管你可以說出一大打的名字,你會準(zhǔn)備為你的下一個項目選擇一種新的JVM語言么? 如今借助來自...

    phodal 評論0 收藏0
  • 函數(shù)入門(什么是函數(shù)編程)

    摘要:第一節(jié)函數(shù)式范式什么是函數(shù)式編程函數(shù)式編程英語或稱函數(shù)程序設(shè)計,又稱泛函編程,是一種編程范型,它將電腦運算視為數(shù)學(xué)上的函數(shù)計算,并且避免使用程序狀態(tài)以及易變對象。 第一節(jié) 函數(shù)式范式 1. 什么是函數(shù)式編程 函數(shù)式編程(英語:functional programming)或稱函數(shù)程序設(shè)計,又稱泛函編程,是一種編程范型,它將電腦運算視為數(shù)學(xué)上的函數(shù)計算,并且避免使用程序狀態(tài)以及易變對...

    StonePanda 評論0 收藏0
  • 《Java 8函數(shù)編程》作者Richard Warbourton:Java的亮點不是語言本身

    摘要:根據(jù)對社區(qū)和新特性的深刻理解,他創(chuàng)作了函數(shù)式編程一書。問你在倫敦社區(qū)的經(jīng)歷是否幫助你創(chuàng)作了函數(shù)式編程這本書絕對是這樣。我認(rèn)為引入函數(shù)式編程會為很多編程任務(wù)提供方便。問之前的是面向?qū)ο蟮?,現(xiàn)在全面支持函數(shù)式編程。 非商業(yè)轉(zhuǎn)載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/199271 Richard Warburto...

    mzlogin 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<