摘要:匹配器是一個一元函數,入參為,返回值為,是一種典型的謂詞。執行器也是一個一元函數,入參為,返回值為,其本質就是定制常見的操作,將定義域映射到值域。為一個工廠類,用于生產各種。其中,使用了的。
形式化Functional programming leads to deep insights into the nature of computation. -- Martin Odersky
FizzBuzzWhizz詳細描述請自行查閱相關資料。此處以3, 5, 7為例,形式化地描述一下問題。
r1 - times(3) -> Fizz - times(5) -> Buzz - times(7) -> Whizz r2 - times(3) && times(5) && times(7) -> FizzBuzzWhizz - times(3) && times(5) -> FizzBuzz - times(3) && times(7) -> FizzWhizz - times(5) && times(7) -> BuzzWhizz r3 - contains(3) -> Fizz - the priority of contains(3) is highest rd - others -> others
接下來我將使用Scala嘗試FizzBuzzWhizz問題的設計和實現。
語義模型從上面的形式化描述,可以很容易地得到FizzBuzzWhizz問題的語義模型。
Rule: (Int) -> String Matcher: (Int) -> Boolean Action: (Int) -> String
其中,Rule存在三種基本的類型:
Rule ::= atom | allof | anyof
三者之間構成了「樹型」結構。
atom: (Matcher, Action) -> String allof(rule1, rule2, ...): rule1 && rule2 && ... anyof(rule1, rule2, ...): rule1 || rule2 || ...測試用例
借助Java8增強了的「函數式」能力,可拋棄掉很多重復的「樣板代碼」,使得設計更加簡單、漂亮。此外,Java8構造DSL的能力也相當值得稱贊,非常直接,簡單。測試用例此處選擇Spock(基于Groovy語言),可提高用例的可讀性和可維護性。
class RuleSpec extends Specification { private static def spec() { Rule r1_3 = atom(times(3), to("Fizz")) Rule r1_5 = atom(times(5), to("Buzz")) Rule r1_7 = atom(times(7), to("Whizz")) Rule r1 = anyof(r1_3, r1_5, r1_7) Rule r2 = anyof(allof(r1_3, r1_5, r1_7), allof(r1_3, r1_5), allof(r1_3, r1_7), allof(r1_5, r1_7)) Rule r3 = atom(contains(3), to("Fizz")) Rule rd = atom(always(true), nop()) anyof(r3, r2, r1, rd) } def "fizz buzz whizz"() { expect: spec().apply(n) == expect where: n | expect 3 | "Fizz" 5 | "Buzz" 7 | "Whizz" 3 * 5 * 7 | "FizzBuzzWhizz" 3 * 5 | "FizzBuzz" 3 * 7 | "FizzWhizz" (5 * 7) * 2 | "BuzzWhizz" 13 | "Fizz" 35 /* 5*7 */ | "Fizz" /* not "BuzzWhizz" */ 2 | "2" } }匹配器:Matcher
Matcher是一個「一元函數」,入參為Int,返回值為Boolean,是一種典型的「謂詞」。從OO的角度看,always是一種典型的Null Object。
import static java.lang.String.valueOf; @FunctionalInterface public interface Matcher { boolean matches(int n); static Matcher times(int n) { return x -> x % n == 0; } static Matcher contains(int n) { return x -> valueOf(x).contains(valueOf(n)); } static Matcher always(boolean bool) { return n -> bool; } }執行器:Action
Action也是一個「一元函數」,入參為Int,返回值為String,其本質就是定制常見的map操作,將定義域映射到值域。
@FunctionalInterface public interface Action { String to(int n); static Action to(String str) { return n -> str; } static Action nop() { return n -> String.valueOf(n); } }規則:Rule
Composition Everywhere
Rule是FizzBuzzWhizz最核心的抽象,也是設計的靈魂所在。從語義上Rule分為2種基本類型,并且兩者之間形成了優美的、隱式的「樹型」結構,體現了「組合式設計」的強大威力。
Atom
Compositions: anyof, allof
Rule是一個「二元函數」,入參為(Int),返回值為String。
@FunctionalInterface public interface Rule { String apply(int n); }
Rules為一個工廠類,用于生產各種Rule。其中,allof, anyof使用了Java8 Stream的API。
public final class Rules { public static Rule atom(Matcher matcher, Action action) { return n -> matcher.matches(n) ? action.to(n) : ""; } public static Rule anyof(Rule... rules) { return n ->sstream(n, rules) .filter(s -> !s.isEmpty()) .findFirst() .orElse(""); } public static Rule allof(Rule... rules) { return n -> sstream(n, rules) .collect(joining()); } private static Stream源代碼sstream(int n, Rule[] rules) { return Arrays.stream(rules) .map(r -> r.apply(n)); } private Rules() { } }
Github: https://github.com/horance-liu/fizz-buzz...
C++11參考實現: https://codingstyle.cn/topics/97
Scala參考實現: https://codingstyle.cn/topics/99
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/65591.html
摘要:背景上的一道原題,通過格式劃字符串精簡了代碼結構,省去了很多條件判斷語句。題目描述解題思路題目是很簡單的,關鍵是如何優雅地完成是否在當前時間單位后添加和或者,我的代碼里運用了很多語句。代碼感想表達式真是一個神器。 背景 CodeWar上的一道原題,通過格式劃字符串精簡了代碼結構,省去了很多條件判斷語句。 題目描述 Your task in order to complete this ...
摘要:題目從給定字符串中隨機出的三字符列表的集合中,恢復原始字符串,并且三字符列表按字符在字符串中出現順序排列。作為簡化,假設秘密字符串中不會有重復字母。從原始集合中去掉找出的第一個字母,并在除去字母的該行末尾添加,以保持三元素列表。 題目:從給定字符串中隨機出的三字符列表的集合中,恢復原始字符串,并且三字符列表按字符在字符串中出現順序排列。作為簡化,假設秘密字符串中不會有重復字母。如下: ...
摘要:題目給出一個整型數列表和一個整數,求列表中加起來等于的兩個數,并且這一對是在列表中最先組成對的。因為題目要求是返回最先組對成功的兩個數,所以要找到列表中符合要求的數對中,第二個數最先出現的數對。與擁有類似的結構。 題目:給出一個整型數列表和一個整數sum,求列表中加起來等于sum的兩個數,并且這一對是在列表中最先組成對的。 這道題并不難,使用兩個for循環很容易做出來。但提交答案時說出...
閱讀 2217·2021-11-19 09:40
閱讀 1928·2021-11-08 13:24
閱讀 2462·2021-10-18 13:24
閱讀 2864·2021-10-11 10:57
閱讀 3590·2021-09-22 15:42
閱讀 1124·2019-08-29 17:11
閱讀 2536·2019-08-29 16:11
閱讀 2429·2019-08-29 11:11