内容简介:ClojuTRE 2016 演講筆記
趁著假日來趕一下進度,於是把我看過的 ClojuTRE 2016 心得/筆記紀錄在這邊。
嗯……其實 ClojuTRE 2016 每一場演講我都看完了…..
當然,我並不是每一場都聽的懂,於是這筆記只能僅供參考,請勿盡信orz…
有些演講真的很難畫重點,還是挑自己有興趣的看吧!!
Using Clojure to provide computerized psychotherapy
講者投影片: 下載連結
這場演講在講 Clojure 用於心理治療 (psychotherapy) 上,一開始講者提出了問題:
對於這些問題,我們可以有一些解法:
而更多的問題,則是沒有足夠的人手在心裡治療上,因此講者提到了可以透過電腦來協助,點子來自於 treatment manuals
而 網路認知行為治療 (iCBT, internet-based Cognitive behavior therapy) 則大部分提供了如上面的那樣的自我治療(sel-help)資訊,這種方式減少了一些問題,比如治療師(therapist)和病患之間的距離
然後後面講者繼續講了一些問題,解法一是用 Clojure 寫了些網頁程式….(嗯,看影片吧) ,而這網頁程式透過 Luminus framework 製作,值得一提的是講者第一個學的程式語言就是 Clojure。
The Universe As A Value
投影片: 下載連結
這場演講第一次聽的時候我傻眼了,於是就再聽了第二次。
講者一開始先稍微講了些關於宇宙 (Universe) 的事情,然後導向愛因斯坦的相對論,我們可以假設有一個觀察者如下
(def observer (atom {:universe u :time t}))
而愛因斯坦說過,時間和觀察者是相對的 (time is relative to observer),兩個不同的觀察者會看到不同的宇宙 (Universe),也就是說,有許多不同的宇宙(Universe)存在。
我們可以定義 這個符號為所有可能可以觀察到的宇宙空間( is the set of all possible observable universes),因此,我們就可以定義 Clojure 程式用來選擇下一個 Universe。
(defn next-u "Given an observed universe u, return a possible 'next' universe." [u t] (rand-nth (filter #(consistent? % u t) 핌)))
而下一個程式碼,則是讓一個觀察者 (observer) 切換到另外一組 Universe 去
(defn switch-universe! "Put the given observer in another universe" [observer] (swap! (fn [{:keys [universe time]}] {:universe (next-u universe time) :time (inc time)}) observer))
而我們可以這樣執行我們的觀察者:
(defn run-observer "Run the observer, giving them the impression of passing time" [observer] (dorun (iterate switch-universe! observer)))
接下來接到了 Pump-probe technique ,嗯…我不知道他在講啥 (摀臉)….所以只好秀一下他接下來的投影片:
接下來話鋒一轉,突然變成說…在 ClojureScript 中,無論是 Om 或是 Reagent, 我們都有一個地方定義 app state (universe)
;; The app 'universe' (def app-state (atom {:drawer {:items [{:name "ear-plugs"}]} shopping {:items [{:name "Coffee" :quantity 2} {:name "Milk" :quantity 2} {:name "Bird seed" :quantity :lots}]}}))
接著我們就可以用 deref 去查看我們的 Universe (app state)
(deref app-state) ;; or @app-state
而在這種狀況下,我們滿足了以下兩種規範:
-
Consistency
In the render phase, the value we render is constant
-
Concurrency
We can take our time, nobody is waiting for us!
這種app-state的形式和物件導向 (Object Orientation) 是不同的,我們知道物件導向是這樣的:
Object Orientation: Lots of changing state, scatered around.
講者舉 https://juxt.pro/ 為例,這個網站有很多 state 要去處理,因此我們可以做一個 record 去弄這些 state
(defrecord AppState [data-sources] clojure.lang.IDeref (deref [this] (skup/refresh! this) ;; Return the 'universe as a value' )) ;; Skippy McSkipface: https://github.com/juxt/skip
接下來我們就可以對這些 state 進行 derefernece 的動作
那要怎樣提昇 referesh 的效能呢?我們可以透過這些支援 time-travel 的 工具 來進行:
而在開發環境,則可以透過 background watchers 來對資料進行更新的動作
而這樣做,講者提出了一個結果:
嗯…我必須承認我聽了兩次還是聽不太懂 = =
最後講者對比了一下 C 和 Lisp:
It seems to me that there have been two really clean, consistent models of programming so far: the C model and the Lisp model.
– Paul Graham
"You're not constructing it like making a tone of source code and compiling it periodically, you're constructing it the way you construct a city: build some of it, it's running all the time, so it's kind of like a live programming language."
– Dick Gabriel On Lisp, Software Engineering Radio Episode 84
Native mobile apps with ClojureScript
終於有看到一場在講 react-native 作用於 ClojureScript 上的演講!! 這之前我有稍微玩過,但沒認真寫這樣的程式。
關於 ClojureScript 作用在 react-native 上的資料,可以到 http://cljsrn.org/ 去找,或是 Clojurians 的 Slack #cljsrn
頻道。
這場演講先從 react-native 開始介紹,說明它和 Cordova/HTML5 的不同:
接下來則是以開發者的觀點來看 react-native,一個基本的 react-native 程式長這樣:
import React, { Component } from 'react'; import { Text, View } from 'react-native'; class WhyReactNativeIsSoGreat extends Component { render() { return ( <View> <Text> If you like React on the web, yoou'll like React Native. </Text> <Text> You just use native components like 'View' and 'Text', instead of web components like 'div' and 'span'. </Text> </View> ); } }
而 ClojureScript 的相對應改寫則是:
(ns rn-example.core (:require [reagent.core :as r])) (def react-native (js/require "react-native/Libraries/react-native/react-native.js")) (def view (r/adapt-react-class (.-View react-native))) (def text (r/adapt-react-class (.-Text react-native))) (defn why-react-native-is-so-great [] [view [text "If you like React on the web, you'll like React Nateive"] [text "You just use native components like 'View' and 'Text' instead of web components like 'div' and 'span'."]])
由上面範例可以看到,除了一開始載入一些 javascript 函式庫需要比較骯髒的手段外,剩下的就很純粹是 Clojure 的資料結構的處理。
而在 ClojureScript 上面,目前有兩個 build tools 針對 ClojureScript 在 react-native 上的:
講者是這樣評論這兩套工具的:
-
boot-react-native
Uses boot, works closer to the RN packager but is slower and inferior out of the box experience (persornal experience)
-
re-natal
Uses leinigen, runtime errors are not traceable, templates for re-frame, om.next and rum
而最常用的前端框架則是基於 reagent 的 re-frame 。
測試方面,則是需要透過 react-native-mock
去對 ract-native 組件進行測試,圖片和函式庫則是透過 mockery
來進行測試。
至於效能的比較,就直接看投影片吧:
Isomorphic web apps with Rum
本場次為 rum 這個 ClojureScript 對於 React.js 的封裝的作者的演講,講者 tonsky 同時也是許多知名 Clojure/Script 函式庫專案的維護者。
tonsky 一開始介紹幾種不同在 ClojureScript 上對於 React.js 的封裝函式庫,然後介紹自己設計 rum 的幾個動機,其中一個是更好的與 datascript 或是其他資料儲存函式庫相容。
所以基本的 rum 程式長怎樣呢?
(rum/defc label [text class] [:div.lbl {:class class} text]) (rum/mount (label "Hello" "header") js/document.body)
包含 state 的複雜點的範例則是:
(def mixin {:will-mount (fn [state] (assoc state :key (atom nil)))}) (rum/defc label < mixin [text class] ([:div.label {:class class} text]))
而 rum 也支援 serveri-side 渲染 ( Om.Next 也支援囉~ ),運作的流程是這樣:
那用 rum 有什麼好處呢?講者提出了以下幾點:
- Complex single-page apps with fine control
- Custom/mixed state models
- Server-side rendering and templating
而用 rum 的壞處則是:
- Doesn't teach you how to write apps
The Story of Sir Owl Lisp
Doing data science with Clojure: the good, the bad, the ugly
投影片連結: 線上看
Easy things should be easy and hard things should be possible.
– L. Wall
老實說我聽不太懂講者在講什麼….. Orz…
不過講者提到一個他寫的函式庫:
然後…我還是聽不懂,所以只好把他 quote 的名言秀一下了 orz…
This is possibly Clojure's most important property: the syntax expresses the code's semantic layers. An experienced reader of Clojure can skip over most of the code and have a lossless understanding of its highlevel intent.
– Z.Tellman, Elements of Clojure
接下來講者稍微提到了 clojure.spec 這個預計要在 Clojure 1.9 加入的函式庫,可以減少查找問題的時間,以及 gorilla-repl 這種類似 ipython notebook 的工具。
在後面,講者終於講到前面他說的函式庫 huri , 你可以透過他在 gorilla-repl 上畫圖。
Interactive Clojure code snippets in any web page with KLIPSE
Distributed transducers
投影片連結: 點我下載
本篇講述講者實作分佈式版的 fold 函式,並透過 AWS lambda 來加速運作。
講者提供了一個查找類似詞的函式來描述整個要解決問題的狀況:
(defn similar-words-1 [word words min-distance] (->> words (map (partial levensthein-distance word)) (filter (fn [[d _]] (<= d min-distance))) (reduce group-by-distance {}))) (similar-words-1 "word" ["sword" "lord" "card" "cat"] 2) ;; => {1 #{"sword" "lord"}, 2 #{"card"}}
當然我們可以把這樣的程式改用 transducer 改寫,來提昇程式的效能
(defn similar-words-2 [word words min-distance] (transduce (comp (map (partial levensthein-distance word)) (filter (fn [[d _]] (<= d min-distance)))) group-by-distance words))
但是這樣的程式無法並行運算,因此我們再用 fold 來改寫
(defn similar-words-3 [word words min-distance] (r/fold (partial merge-with concat) group-by-distance (r/folder words (comp (map (partial levensthein-distance word)) (filter (fn [[d _]] (<= d min-distance)))))))
不過有一個問題,fold 會同時執行兩個函式,一個用來執行 reduce,稱為 reducing function
,另外一個則是用來合併結果,稱為 combining function
,而 reducing function
會並行的執行。( 參考資料 )
fold uses two functions: a "reducing" function, which it calls as a regular reduce across segments of the input collection, and a "combining" function, which combines the results of these reductions.
因此我們可以再把這個程式改寫
(defn similar-words-4 [word words min-distance] (r/fold (partial merge-with concat) ((comp (map (partial levensthein-distance word)) (filter (fn [[d _]] (<= d min-distance)))) group-by-distance) words))
這樣改寫後,效果好多了,但是還有最後一個問題: 並行化的 fold 只能運作在 non-lazy sequence 上,於是再加一些手腳。
(defn similar-words-5 [word words min-distance] (r/fold (partial merge-with concat) ((comp (map (partial levensthein-distance word)) (filter (fn [[d _]] (<= d min-distance)))) group-by-distance) (vec words)))
跑出來的結果如下,在講者的 HP zBook 筆電 (i7 雙核)上執行的結果是這樣的
- 一般版本: ~175 s
- Transducer: ~170 s
- Parallel fold: ~108 s
做完這些測試後,講者想到了,是否分佈式的 fold 可以提供更好的效能?
講者選用了 AWS Lambda 以及 Amazon SQS 來進行這個測試,整體的架構是這個樣子的:
接下來你要在你的 project.clj 加入以下這些設定
:plugins [[lein-clj-lambda "0.5.1"]] :lambda {"demo" [{:handler "distributed-transducers-poc.LambdaFn" :memory-size 1536 :timeout 300 :function-name "distributed-transducers-poc" :region "eu-west-1" :policy-statements [{:Effect "Allow" :Action ["sqs:*"] :Resource ["arn:aws:sqs:eu-west-1:*"]}] :s3 {:bucket "mhjort-distributed-transducers-poc" :object-key "lambda.jar"}}]}
然後使用下面命令進行 deploy
lein lambda install demo
講者給出了範例,示範用 fold 以及 dfold 執行程式的狀況
(ns distributed-transducers-poc.demo (:require [distributed-transducers-ppc.rc :refer [dfold]] [clojure.core.reducers :as r])) (r/fold + ((map inc) +) (range 100000)) (dfold + ((map inc) +) (range 100000) 2) ; <= 2 is how many instance you run
那… 哪些資料會被送到 SQS 呢?
- 要被執行的東西 (Chunk of items to be processed)
- Reduct function
而在最後,使用分佈式 fold 的程式會變成這樣
(defn similar-words-6 [word words min-distance] (dfold (partial merge-with concat) ((comp (map (partial levensthein-distance word)) (filter (fn [[d _]] (<= d min-distance)))) group-by-distance) (vec words) 10))
而最後整體測試結果則是:
- 筆電 (一般): ~175 s
- 筆電 (transducer): ~170 s
- 筆電 (parallel fold): ~108 s
- AWS Lambda (10 nodes, cost 0.01 $): ~40 s
- AWS Lambda (20 nodes, cost 0.02 $): ~28 s
Introduction to clojure.spec - Arne Brasseur
講者為 LambdaIsland 的維護者,該網站提供了一系列的 Clojure/ClojureScript 教學,若有興趣的話可以付費訂閱。
clojure.spec 是 Clojure 預計在 1.9 版加入的新功能,對於 Clojure 這種動態型別語言而言,雖然容易開發,但是一旦你傳送給函式的型別不對,就很可能造成除錯不易。
在 clojure.spec 出現之前,比較有名的型別檢查是 core.typed 以及 schema ,而 clojure.spec 將會成為 buildin 在 Clojure 的一部分函式。
clojure.spec 的加入並不會導致程式執行變慢,用到他的時間只有在開發時使用 REPL 以及編譯的時候,所以到底要怎樣用呢?
如果你是 leinigen 的用戶,更改你的 project.clj
成如下
(defperoject myproject "0.1.0-SNAPAHOT" :dependencies [[org.clojure/clojure "1.9.0-alpha13"]])
boot 的用戶則是在你的 build.boot
加入
(set-env! :dependencies '[[org.clojure/clojure "1.9.0-alpha13"]])
於是讓我們開始使用 clojure.spec 吧! 講者假設現在有一個機器人主廚 (Robot Chef) 正在弄一份菜單 (recipes),而這份菜單內容是這樣的:
(def tomato-sauce-recipe {:robochef/ingredients [250 :g "peeled tomatoes" 3 :clove "garlic" 5 :g "pepper"] :robochef/steps ["heat a pan" "throw everything in" "stir"]})
像這種透過 / (slash) 組成的 keyword (關鍵字),我們稱呼為 namespace keyword
:grettings/kittos ;; => :grettings/kittos
為何要用 namespace keyword 呢?一個原因是可以避免到名稱衝突,所以我們可以把所有的 keyword 合併在同一個 map 中
{:http/method :get :robochef/method :stir}
實際上在 Clojure 中,變數也是包含在 namespace 中的
(ns robochef.core) (def ingredents {,,,}) :robochef.core/ingredients ;; => :robochef.core/ingredients ::ingredients ;; => :robochef.core/ingredients
也因此,在一個 map 中使用 namespace 作為 prefix 是很常見的
{:robochef/recipe-name "..." :robochef/ingredients [,,,] :robochef/steps [,,,] :robochef/cooking-time 30}
而在 Clojure 1.9 中,將會有新的語法可以把上面的東西變成這樣
(def recipe #:robochef{:recipes-name "" :ingredients [,,,] :steps [,,,] :cooking-time 30}) (let [{:robochef/keys [steps serves]} recipe] (doseq [s steps] ,,,))
在了解這些前置訊息後,我們終於可以來到 clojure.spec 了,首先我們把 clojure.spec 的命名空間(namespace) 指定為 s
,接下來我們加入以下這些 spec,這會將這些 spec 加入到全域去 (global registry)
(ns robochef.core (:require [clojure.spec :as s])) ;; keep in mind ::recipe == :robochef.core/recipe (s/def ::recipe (s/keys :req [::ingredients] :opt [::steps])) (s/def ::ingredients (s/* (s/cat :amount number? :unit keyword? :name string?))) (s/def ::steps ,,,)
好了後,我們就可以這樣去驗證,符合 spec 的狀況是這樣的
(s/valid? ::robochef/ingredients [5 :g "tea"]) ;; => true (s/conform :robochef/ingredients [5 :g "tea"]) ;; [{:amount 5, :unit :g, :name "tea"}]
那錯誤的情況呢? 我們可以透過 clojure.spec/explain
來幫我們找出狀況
(s/valid? ::robochef/ingredients ["10" :g "tea"]) ;; => false (s/conform :robochef/ingredients ["10" :g "tea"]) ;; => :clojure.spec/invalid (s/explain :robochef/ingredients ["10" :g "tea"]) ;; In: [0] val: "10" fails spec: ;; :robochef/ingredients at: [:amount] predicate: number?
我們也可以用 generator 去產生符合數量並可以通過測試的結果
(s/exercise :robochef/ingredients 2) ;; ([() []] ;; [(0 :Hi "0") [{:amount 0, :unit :Hi, :name "0"}]])
更多的內容我還在消化中,就請看影片吧 ~
後面演講則稍微提到一下 test.check 這個測試用的函式庫。
Clojure of Things
The Next Five Years of ClojureScript
這場是目前 ClojureScript 主要維護者 David Nolen 環顧了過去幾年 ClojureScript 開始開發的狀況,以及未來的情況。
在這場演講後半段也提及到如何參與 ClojureScript 推廣/開發等議題,也有人提問 David Nolen 對於 WebAssembly 的看法等等。
這場演講我覺的蠻不錯的,很喜歡這種有講故事風格的演講。
以上所述就是小编给大家介绍的《ClojuTRE 2016 演講筆記》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Learn Python the Hard Way
Zed A. Shaw / Addison-Wesley Professional / 2013-10-11 / USD 39.99
Master Python and become a programmer-even if you never thought you could! This breakthrough book and CD can help practically anyone get started in programming. It's called "The Hard Way," but it's re......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!