Clojure 的发展情况

Clojure 是 Lisp 对 JVM 的抱大腿行为

我猜,由于 Clojure 是 Lisp 方言的原因,在国内,Clojure 的使用真的很少很少,cn-clojure 这个国内的 Clojure 用户组的人气也不高。

于是,我提了一个问题, Clojure的发展情况如何? ,也做了些查询,汇总下信息

国内使用 Clojure 的公司

  1. 一个比较大的公司是 AVOS ,是前 Youtube 创始人的公司,后端基本都是用 Clojure 来写的。
  2. 中瑞财富 p2p 互联网金融项目
  3. 百思 一个社交网站数据分析的公司
  4. 深圳风林火山 - 一家游戏公司:深圳风林火山,游戏产品黄金岛牌类游戏,目前使用 Clojure 作为主力服 务器开发语言。我们目前使用的 Clojure 技术都在刀锋上,非常前卫。使用 ClojureScript 和 Clojure 结合的开发框架目前正在产品化中,其中使用到的 ClojureScript 和 One 的新特性由 Clojure Core 团队开发,使用 Datomic 数据库。 我们的项目在第一次 ClojureConj 大会上作为 Aaron Bedra 介绍的 Clojure in the Field (Clojure 用于实战)的重要项目介绍。
  5. 直播贴 一家八卦网站,也 正在招人

金融系统

Clojure 的很多代码都是银行的业务作为例子,比如下面这个,所以以为会有比较多的金融行业应用,但是实际上没看到。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(def account1 (ref 100))
(def account2 (ref 0))
;; ; to read the current value of a ref, use (deref refname):
;; ;=> (deref account1)
;; 100
;; ;=> @account1 ; @refname is equivalent to (deref refname)
;; 100
(defn transfer [amount from to]
(dosync
(alter from - amount) ; alter from => (- @from amount)
(alter to + amount))) ; alter to => (+ @to amount)
;; ;=> @account1
;; 100
;; ;=> @account2
;; 0
;; ;=> (transfer 100 account1 account2)
;; 100
;; ;=> @account1
;; 0
;; ;=> @account2
;; 100

这个例子中,应用了 Clojure 的 STM 机制保证转账操作能都完毕,参见 [1]

1
2
(alter from - amount)
(alter to + amount)

搜索了下国外的情况,其实应用也不多,有 citi (花旗银行)、 UBS (瑞士联合银行) ,但是好像实际用的也不多。有一段评价[2]:


Based on my own experience and conversations with others who work in the City, there’s a small but increasing move towards functional languages. I have to say that by far the most common I’ve heard of are Scala or F#, with ML and Clojure far behind.

也就是说金融行业虽然也在往函数式语言靠,但是F# 和 Scala 的使用更广泛,远高于 ML 和 Clojure 这样的语言。

Clojure 语言本身的发展情况

  1. 特性变化还是挺多的,版本更新时,有 core.* 下面的更新
  2. 库变更也比较频繁:我目前借的两本书,《Clojure 编程》 和 《Clojure 程序设计》,内容都稍微有点过时,导致有些例子不能运行
  3. 语法发展也可以看下 这个帖子 ,dennis zhuang 的回复,他本人就是在 AVOS 工作

REFS

[1] http://chaifeng.com/clojure-stm-what-why-how/

[2] http://mdavey.wordpress.com/2013/05/24/clojure-in-finance/ 的评论

学习 clojure 3 :《Clojure程序设计》 Clojure 编程入门 - 在 repl 中测试代码

继续探索 repl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
; CIDER 0.7.0alpha (package: 20140711.835) (Java 1.7.0_55, Clojure 1.5.1, nREPL 0.2.3, cider-nrepl 0.7.0-snapshot)
user> (defn hello [name]
(str "Hello, " name)) ;; str 将列表转为字符串
#'user/hello
user> (hello "tom")
"Hello, tom"
user> *1 ; *1 *2 *3 分别存储了 repl 的最近3次求职
"Hello, tom"
user> (/ 1 0) ;; 0 是不能作为分母的,会报错
ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:156)
user> ;; *e 存储了最后一个异常的的信息
user> *e
#<ArithmeticException java.lang.ArithmeticException: Divide by zero>
user> (pst) ;; print stacktrace 得到堆栈信息
CompilerException java.lang.RuntimeException: Unable to resolve symbol: pst in this context, compiling:(/private/var/folders/nt/gkh1mbhn4pncwb79gmrfr9740000gn/T/form-init5253497584462403679.clj:1:1)
user> ;; 额,好像 pst 这个函数不存在了:1.3.0 之后,pst 放到 clojure.repl/pst 了,需要引入 (use 'clojure.repl),见后面
user> (load-file "tmp.clj") ;; 加载 tmp.clj ,里面的定义会导入 到 user 命名空间下来 : (def a 1)
#'user/a
user> a ;;
1

查找文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
user> (use '[clojure.repl :only (doc)]) ;; 从 coljure.repl 中导入 doc
nil
user> (doc str) ;; 使用 doc 来查找函数的文档
-------------------------
clojure.core/str
([] [x] [x & ys])
With no args, returns the empty string. With one arg x, returns
x.toString(). (str nil) returns the empty string. With more than
one arg, returns the concatenation of the str values of the args.
nil
user> (use '[clojure.repl :only (find-doc)])
nil
user> (find-doc "reduce") ;; 在导入一个 find-doc 函数,支持正则或者字符串查找
-------------------------
clojure.core/areduce
([a idx ret init expr])
Macro
Reduces an expression across an array a, using an index named idx,
and return value named ret, initialized to init, setting ret to the
evaluation of expr at each step, returning ret.
-------------------------
clojure.core/reduce
([f coll] [f val coll])
f should be a function of 2 arguments. If val is not supplied,
returns the result of applying f to the first 2 items in coll, then
...

查看函数源码

1
2
3
4
5
6
7
8
9
user> (use '[clojure.repl :only (source)])
nil
user> (source identity)
(defn identity
"Returns its argument."
{:added "1.0"
:static true}
[x] x)
nil

修改用户配置文件,引入常用的工具函数

像上面的 docfind 等函数需要 use 才能使用,为方便起见,可以在repl启动时,就载入,只需在 ~/.lein/user.clj 添加

1
2
3
4
;; 1.3.0 之后,将 doc source 等放到了 clojure.repl 中,可以在启动 repl时导入
(if (>= (.compareTo (clojure-version) "1.3.0") 0)
(do (use 'clojure.repl)
(use 'clojure.java.javadoc)))

这样,每次启动 repl 都能直接使用这些函数了

学习 clojure 2 : 《Clojure程序设计》 Clojure 简介

Clojure 是一种基于 Java 虚拟机 (Java Virtual Machine)的动态编程语言,支持函数式编程,简化并发编程,能调用 Java 程序

什么函数式编程?程序的功能单位是无副作用的函数,输入确定,输出就确定,就像数学上的函数一样。

相对传统的面向对象方式——复杂的对象关系图,基于状态变量,函数式编程提供了另外一种解决问题的思路。

示例:使用 userequire 引入非核心库

1
2
3
4
5
6
7
8
9
10
; CIDER 0.7.0alpha (package: 20140711.835) (Java 1.7.0_55, Clojure 1.5.1, nREPL 0.2.3, cider-nrepl 0.7.0-snapshot)
user> (use '[clojure.java.io :only (file)])
nil
user> (file "README.md")
#<File README.md>
user> (require '[clojure.java.io :as io])
nil
user> (io/file "README.md")
#<File README.md>
user> ;; user> 标明了当前所在的 Clojure 名字空间

示例:短小简洁的函数式风格代码

一个判断是否是空字符串的函数

用Java 来写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StringUtils {
public static boolean isBlank(String str){
int strLen;
if(str == null || (strLen = str.length()) == 0){
return true;
}
for(int i = 0;i < strLen;i++){
if((Character.isWhiespace(str.charAt(i)) == false)){
return false;
}
}
return true;
}
}

用Clojure 来写:

1
2
(defn blank? [str]
(every? #(Character/isWhitespace %) str))

短小多了吧!

值得的注意的是,Clojure版本的代码,噪音非常低,而Java的看起来很啰嗦,使用了更多的语法关键词,如 public , class , boolean

与 Java 等其它 C 系的语言不同,Clojure 中 ? 也是可以作为函数名字的,Lisp系的语法关键词要少,因此显得简单优雅,这种简单优雅,是因为 Lisp 语言的构成单位括号表达式所带来的,括号表达式对与很多人来说显得很怪异,不过习惯了,就会喜欢上括号表示的,特别是Emacs对括号表达式的支持非常好,有一个 par-mode 可以对括号表达式,进行非常快速高效的编辑变换。

上面 Clojure 代码中的的 every? 是接受两个参数,一个函数 f #(Character/isWhitespace %) 和一个 c - collection 做为参数,注意,以函数为参数是函数式语言的特性,函数是可以参数传递的。对于collection中的元素,本例中即是strf 作用于 c 的每一个元素,都返回为真的话,那么 every? 也返回为真。

示例:defrecord

创建 records

1
2
3
4
5
6
7
8
9
10
user> (defrecord Person [first-name last-name])
user.Person
user> (def foo (->Person "Jinwei" "Tang"))
#'user/foo
user> foo
#user.Person{:first-name "Jinwei", :last-name "Tang"}
user> (:first-name foo) ;; 访问
"Jinwei"
user> (:last-name foo)
"Tang"

records 不可改变,records are immutable,但是可以通过 assoc 或者 merge 从原有的 records 创建新的 records

1
2
3
4
5
6
user> (assoc foo :sex "male")
#user.Person{:first-name "Jinwei", :last-name "Tang", :sex "male"}
user> foo ;; 原来的 foo 不变
#user.Person{:first-name "Jinwei", :last-name "Tang"}
user> (merge foo {:sex "male"}) ;; 也可以使用 merge 创建新的 records
#user.Person{:first-name "Jinwei", :last-name "Tang", :sex "male"}

创建带默认值的 record [1]

(defrecord Foo [a b c])

(defn make-foo
[& {:keys [a b c] :or {a 5 c 7}}]
(Foo. a b c))

(make-foo :b 6)
(make-foo :b 6 :a 8)

什么时候使用 record

很多时候,mapsstructs 即可完成大部分工作,可为什么还要使用 record 呢? 这里 有介绍.

records 就是 Java class instances (not Clojure maps),具有更好的性能。

Clojure 的一些特性

  1. 参数的容器是一个向量 [] ,而不是列表 ()

    1
    2
    (defn hello-world [user]
    (println (format "Hello, %s" user)))
  2. 相比Common Lisp简少了括号
    Common Lisp
    1
    2
    (cond ((= x 10) "equal")
    ((> x 10) "more"))

    Clojure
    1
    2
    (cond (= x 10) "equal"
    (> x 10) "more")

    Clojure 中的并发编程示例:dosync

1
2
3
4
5
6
7
user> (def accounts (ref #{}))
#'user/accounts
user> (defrecord Account [id balance])
user.Account
user> (dosync
(alter accounts conj (Account. "CLJ" 1000.00)))
#{#user.Account{:id "CLJ", :balance 1000.0}}

ref 创建了一个引用,dosync 开启了一个事务,事务能不用Java的锁定机制来更新 可变数据 。事务使用了 (STM, software transactional memory) 来支持并发。

什么是 STM 呢?


Software Transactional Memory (STM) is a concurrency control technique
analogous to database transactions for controlling access to shared
memory in concurrent computing. It is an alternative to lock based synchronization.

STM 通过过 ref and dosync 来构建。如上面的例子所示。

上面的示例,可能不是特别好,可以看参考 [2] 的银行转账的示例

直接访问 Java API

访问 JavaAPI

1
2
3
4
5
user> System
java.lang.System
user> (System/getProperties)
{"java.runtime.name" "Java(TM) SE Runtime Environment", "sun...
...many more...

Clojure 为访问 JavaAPI 提供了语法糖

在 Java 中的方式:

1
"hello".getClass().getProtectionDomain()

Clojure 语法糖访问:

1
2
3
4
5
6
7
8
user> (.. "hello" getClass getProtectionDomain)
#<ProtectionDomain ProtectionDomain null
null
<no principals>
java.security.Permissions@7e8027cd (
("java.security.AllPermission" "<all permissions>" "<all actions>")
)

Clojure 实现 Java 接口

Clojure 提供了简单的函数用于实现 Java 接口,以及从 Java 基类派生。Clojure 的所有函数都实现了 Callable 和 Runnable 接口,下面使用匿名函数创建 Java 线程:

1
2
3
user> (.run (new Thread (fn [] (println "Hello" (Thread/currentThread)))))
Hello #<Thread Thread[nREPL-worker-15,5,main]>
nil

REF

[1] http://stackoverflow.com/questions/5634188/how-to-set-default-values-for-fields-in-records-in-clojure

[2] http://sw1nn.com/blog/2012/04/11/clojure-stm-what-why-how/

学习 clojure 1:缘起

想学 clojure 是因为看到一篇 blog ,在 pc 上支持 600k 的并发,太疯狂了,比 Node.js
的 250k 两倍还多,于是就心痒痒。并且 clojure 是 lisp 的方言,已知对 lisp 很有兴趣,
但是好像它被一些人人视为「玩具」——除非你特别牛,用它是找不到工作的。而clojure和
Java一样,是基于JVM的语言,所以它可以真的投入使用,比如 Storm 就是 clojure 的应用。

  1. clojure 的高并发能力

    • 因为它是 lock-free 的 [5]
  2. Mac 下安装lein
    在已经有 Java 环境的情况下,安装非常简单:

    1
    brew install leiningen

    然后执行下面的命令,开启 repl

    1
    lein repl
  3. 环境搭建:Emacs+cider [4]

    • M-x package-install [RET] cider [RET]
    • 使用 lein 创建一个项目
      lein new demo

      0.png

      1.png

      2.png

    • 用 Emacs 打开 demo/src/demo/core.clj,执行 M-x cider-jack-in (或使用快捷键 C-c M-j )开启 nREPL server 以及 Emacs client ,这样就可以在 Emacs 中和后台的 server 交互了
      如果出现如下的报错:ider-jack-in can’t find cider-nrepl

      添加一个文件 ~/.lein/profiles.clj

      1
      {:user {:plugins [[cider/cider-nrepl "0.7.0-SNAPSHOT"]]}}
    • 在编辑器中测试代码:在 demo/src/demo/core.clj 里面

      • C-x C-e 移动光标到s-exp括号后面,就是是执行这个表达式
      • 注意在执行 (foo “hello”) 之前,要执行前面的两个表达式

        3.png

    • 在repl中执行代码

      4.png

    • 使用 lein 在 termial 中执行代码

      5.png

      可以看到,缺少 main 函数,修改下代码

      6.png

      也可以指定为其它的函数为入口函数

      7.png

    • project.clj 的所有配置项目见 https://github.com/technomancy/leiningen/blob/stable/sample.project.clj

    • Emacs 的快捷键见 https://github.com/clojure-emacs/cider cider-mode Keyboard shortcut
  4. 学习 learning 需要 Java 的经验吗?[1]

    • clojure 是lisp的方言,和Java很不相同,所以从语言角度来说,不需要
    • 使用已经存在的Java API,那必须还是要和Java打交道

      You don’t need to write any Java code to use Java APIs from Clojure, but you do need to know enough Java (method signatures, data types etc.) to be able to read the JavaDoc documentation of the APIs and convert this into an appropriate Clojure function call. Often, this is as simple as (.someJavaMethod someJavaObject param1 param2) but sometimes it can be more complex (e.g. when you need to instantiate a subclass of some Java class to pass as a parameter)

    • clojure 是最终会编译为JVM字节码,所以精通Java,应该是有好处的

  5. 在哪里寻找第三方的库?

    • clojure-contrib [8]
    • leiningen [9]
  6. clojure 的中小项目[2]

    • cow-blog [7]
    • 使用 lein 构建一个web应用 guest-book
  7. 甚至有一个 clojure-android 的项目,可以让你在 android 上使用 clojure [6]

    但是这时一个 hobby project ,性能很成问题

Footnotes

[1] http://stackoverflow.com/questions/5721496/learning-java-so-i-can-get-at-clojure

[2] http://stackoverflow.com/questions/329221/medium-size-clojure-sample-application

[3] http://dev.clojure.org/display/community/Clojure%2BSuccess%2BStories

[4] https://github.com/clojure-emacs/cider

[5] http://stackoverflow.com/questions/11031886/is-clojure-lockfree-by-using-lockfree-algorithms

[6] http://clojure-android.info/

[7] https://github.com/briancarper/cow-blog

[8] http://github.com/richhickey/clojure-contrib

[9] http://zef.me/2470/building-clojure-projects-with-leiningen


layout: default
tags :
-cordova
-ios
comments : true

title : iOS 开发的第一印象

第一、贵 ,$99 刀换成人民币要 699 圆

第二、申请流程要填一大堆东西,还有各种申请,要登录各种系统,配置文件(Provisioning Profile) XCode 会代你生成,但是有些又要你自己申请

  1. Certificates xCode 会帮你生成,所以不用操心

  2. Identifiers 需要自己申请,申请后,要等一段时间才能生效[3] ,并且注意和 iTunes connect 上的 bunddle id 要对应上

  3. Provisioning Profiles 要自己生成

第三、给开发者用的系统挺烂的:访问慢,提示在维护;在后台申请了一个 identities id,XCode 操作老是不成功,原来是这个id没有同步,上网一查,不是个案,要等一天左右才能同步

第四、开发完了打包发布,发现再怎么都不能 achive ,解决办法是,device不要选择模拟器

第五、发布时,不断的报错:choose a profile to sign with no identities were available,原因就是第三点里描述的,系统延迟!!而且还要延迟一天左右,见 ref

第六、使用 Webview 真的有点慢,在一个循环里面用了正则表达式测试,就把页面拖的卡死,但是我的这个应用又必须是网页的

附录

[1] http://docs.phonegap.com/en/edge/guide_platforms_ios_index.md.html

[2] http://stackoverflow.com/questions/12825724/applications-must-be-ready-for-upload-on-itunes-connect-before-they-can-be-valid

[3] http://anthonytietjen.blogspot.jp/2012/08/overcoming-trouble-validating-your.html

cordova icon generator

cordova/phonegap 能实现跨平台,在各个平台下有不同的 icon、land screen,作为独立开发者,没有设计师,一切都自己搞的人来说,要做那么多套 icon 和 land screen 真是一件悲痛的事情。仅仅就 iOS 和 android 而言,都要生成这么多的图标,下面这还仅仅是iOS 的:

pic

pic

pic

于是,写了个工具,从一张大图片直接生成所有的 icon 、land screen ,放到了 github 上

注意: 依赖 ImageMagic 的 convert 命令

  1. 在 Mac 下 安装 brew install imagemagick
  2. linux (Ubuntu) 下 apt-get install imagemagick

参加智谷创业培训记——如何写商业计划书

1. 参加过程:

周日晚上6:00-8:00参加智谷创业培训——商业计划辅导,我提前一个小时就
到了下沙浙江理工大学,夜羽是这所学校毕业的.问了下校园里的同学,比较顺利的找
到了 N311 教室,得吃晚饭,于是又出校门找食堂,食堂在校门外宿舍区,我分不清
南北,在挺远的一个地方,好难找到。我在1楼买了一个煎饼果子,才¥6。简单吃了
又回 N311 教室,就我一个人,5:40了都还没人来,拿出 mac 继续码代码。等到
17:50了,我都怀疑自己搞错了,最近老是犯糊涂,买错票,坐错车,来的时候也是做
错了地铁,杭州1号线,往下沙那边走有两个方向,在客运站分叉,一个去临平的,还
有一个是去哪儿的,我正好坐错了方向,又只好折回来,还好,挺快,没有耽误太多
时间。

我一个人来的,自己坐在那儿孤零零的。于是找周围的人搭讪,都是些小朋友。

培训会实际上6:30半过了都还没开始,我问那个培训的老师什么时候开始,我说我住
在城西,得急着赶回去。结果聊上了,问我是什么项目,我大致说了下,结果在接下
来的讲解中,还多次以我的项目为例……

2. 感受:

这次参加培训的主要是在校大学时居多,并且遇到的几个竟然是大一的……我猜,
他们只是想丰富验下生活罢了,创业艰辛

3. 学到的知识:

讲师说,注册公司非常容易,一周就能搞定;杭州市的创业大赛举办了
3年了,无偿给创业团队种子基金,得奖是3w,按讲师的说法是「害了创业团队」;这
次是江干区的组织的创业大赛,是第一年举办,得奖是5w;面向在校大学生,感觉有
点水,讲师的说法是,现在全国找不到一家直接投钱给大学生的,智谷是第一家,智
谷在做「行业投资」,区别于「风险投资」,风险投资方只能通过上市退出,所以要
求很严格。

4. 总结:

参加这次活动最大的意义在于,认识了一群充满梦想的伙伴,创业路上,并不孤单。

5. 图片

1.jpg

2.jpg

3.jpg

4.jpg

5.jpg

6.jpg

7.jpg

8.jpg

iOS 8 发布对Hybrid app有什么影响?

iOS 8 正式发布后,基于 UIWebView 的 Hybrid app 性能有望获得大幅提升.

webview 使用了和 safari javascript 引擎

Hybrid app 是基于 UIWebView 的应用,比如 Phonegap/cordova 最终会将 html/js/css 打
包运行在 UIWebView 中。而在 iOS 8 之前,处于安全的考虑[1],只有 Safari 开启了 JavaScriptCore just-in-time (JIT) 技术,实时的将 javascript 编译为机器码。使用了 JIT 技术有什么影响呢?js的计算能力有 200% - 300% 的提升,见下图 [2] —— 注意是js计算能力,对于非计算密集型的,比如游戏之外的项目,可能性能提升不是那么明显,比如参考[3]提到了一个 Todo MVC 的应用,经他的测试也有 20% 左右的提升.

ios_chrome

ios_safari

需要 Hybrid 应应用框架 Phonegap/cordova 跟进

iOS 8 发布了,如果开发者的应用依赖像 Phonegap/cordova 这样的第三方框架,是不能立马享受到带来的好处的,需要 Phonegap/cordova 从 UIWebView 迁移到 WKWebView API. 不过,网络上还没有看到 cordova 跟进的消息,本身 iOS 的正式发布也要等一段时间,拭目以待吧.

参考

[1] http://www.cnet.com/news/ios-8-grants-new-power-to-rival-browsers-web-based-apps/ One possible reason was security: a JIT compiler essentially creates a new program on the fly and marks the region of memory it’s stored in as executable, and a hacker could potentially abuse that privilege.

[2] http://developer.telerik.com/featured/why-ios-8s-wkwebview-is-a-big-deal-for-hybrid-development/

http://developer.telerik.com/wp-content/uploads/2014/06/Chrome_for_iOS_SunSpider.jpg

http://developer.telerik.com/wp-content/uploads/2014/06/iOS_Safari_SunSpider.jpg

[3] http://developer.telerik.com/featured/why-ios-8s-wkwebview-is-a-big-deal-for-hybrid-development/

[4] http://www.minemobile.com/nitro-javascript-engine-in-ios-phonegap-apps/