iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0

[Day11] Clojure Flow Control (1) if / if-not / for


週日偷懶床上打滾中~

流程控制(Flow control)是每個程式語言都會有的設計,有另一個專有名詞叫做 控制結構(Control Structure)

通常在一段程式碼內的執行順序會有三種執行的方式,

  • 循序(sequence): 一行一行照順序讀 (read line by line from top to bottom and from left to right)
  • 選擇(selection): 根據所選擇符合條件的邏輯,跳到對應適當的程式碼區塊(jump to a different part of the program)
  • 重複(repetition): 重複某個區塊的程式碼 re-run a certain piece code again

前一週的鐵人賽所舉的例子蠻多都是屬於循序(sequence),
因此今天開始也要舉點選擇(selection) 和重複(repetition)的例子,
這樣我們未來寫的clojure程式就可以提高複雜度,從基礎到專業囉~

選擇 Selection / Conditionals

  • if系列

第二天鐵人賽文章就有提到最基本的if else

(if boolean-form  
  then-form  
  optional-else-form)

if

Example: if搭配nil?

nil? 若x結果為nil,會回傳true

用if搭配nil?簡單舉幾個例子:

(if (nil? nil) :true :false)
=> :true

空的

(if (nil? [])  :true :false)
=> :false

(if (nil? [nil])  :true :false)
=> :false

(if (nil? {})  :true :false)
=> :false

當然以上的if只是為了舉超簡單例給初踏進clojure世界看倌們 XD
在前兩天介紹reducefilter練習及延伸思考,
開始有了怎麼簡化語法的想法之後,
發現以上的例子全部都可以再精簡,

如果只是為了判斷,只要有最小的執行單位list就好,連if都不用啦!

(nil? nil)
=> true

(nil? [])
=> false

(nil? [nil])
false

(nil? {})
=> false

if-not

if-not 跟if相反,可以想成其他語言如ruby的unless

Collections裡面的API拿來試用看看:

Example: if-not來搭配 collections function的empty? / every?

empty? 空值為true

(empty? [])
=> true

反例的話,非空值就是false啦~

 (if-not (empty? []) :true :false)
=> :false

如果不想一個一個寫,乾脆一次判斷多一點東東:

查到了every?會檢查是否每個collection的元素都符合條件

例如每個collection member都在set裡

(every? #{"a" "b" "c"} ["a" "b"])
=> true

那我們來用every? 把collection裡的element都用 empty? 來判斷

(every? empty? [ nil "" [] () '() {} #{}])
=> true

(if-not (every? empty? [ nil "" [] () '() {} #{}]) :true :false)
=> :false

迴圈/迭代/重複 (Loops/Iteration/Repeat)

上面?every?的例子聞起來似乎有那麼一點迭代的味道...

我們接下來這裡來介紹flow control裡超級常用的 for

for

(for seq-exprs body-expr)
Takes a vector of one or more binding-form/collection-expr pairs, each followed by zero or more modifiers, and yields a lazy sequence of evaluations of expr.

Collections are iterated in a nested fashion, rightmost fastest, and nested coll-exprs can refer to bindings created in prior binding-forms.

文件裡有講到一個重點 lazy sequence,在這裡先用for舉個簡單的例子,讓range裡的每個值都可以執行list form裡的運算:

(for [x (range 1 6)]
     (* x x))
(1 4 9 16 25 36)

再舉個超展開例子:

let是Clojure的special form,可以透過裝在vector裡建立語意化的bindings(綁定),

(for [x (range 1 6) 
      :let [square-x (* x x) 
            cube-x (* x x x)
            x-to-power-of-four(* x x x x)]] 
  [x square-x cube-x x-to-power-of-four])
  
=> ([1 1 1 1] [2 4 8 16] [3 9 27 81] [4 16 64 256] [5 25 125 625])

以上回傳的是就是傳說中的LazySequence,希望之後幾天的鐵人賽有機會花篇幅來補充!

tutorial.core=> (class(for [x (range 1 6)
           #_=>       :let [square-x (* x x)
           #_=>             cube-x (* x x x)
           #_=>             x-to-power-of-four(* x x x x)]]
           #_=>   [x square-x cube-x x-to-power-of-four]))
clojure.lang.LazySeq

在vector裡第一、第二、第三、第四個元素,
每個元素分別代表著不同數字執行2次方到4次方的結果,
是不是很方便呢?

由於文件裡有提到:

Supported modifiers are: 
:let [binding-form expr ...],
 :while test, :when test.

看起來for當然還能跟不同條件結合!

今天週日先簡單開頭暖身一下flow control,
明天再來花先篇幅介紹 while / when / cond 以及 doseq
:)


上一篇
[Day10] Clojure Functional Programming與資料操作(3) - filter
下一篇
[Day12] Clojure Flow Control (2) while / when / doseq
系列文
後端Developer實戰ClojureScript: Reagent與前端框架 Reframe30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言