タオルケット体操

サツバツいんたーねっと

Clojureの練習に承認欲求システムのクライアントを書いたので所感

ClojarとかよくわかんないのでGitHubにソースがあるだけです。

hachibeeDI/shounin-clj · GitHub

なお承認欲求自動化システムについては以下のエントリが参考になります。
みんなもこれを気に、承認君でインターネット承認欲求の自動化をしましょう。

承認欲求満たすのを自動化した - is Neet

簡素なAPIで完結しているので、練習にちょうど良いかなとおもってネタにしました。

Clojureの使い心地

とても良いです。
Lispって括弧ばっかで可読性低いじゃん……」なんて思っていましたが、Clojureが頑張ってるからか、僕の脳がLispanizedされたからか、普通に読みやすいですね。っていうか引数が[]なだけで全然可読性違いますね。
完結な文法や、実質的にインデントで制御する感じとかはPythonっぽい印象を受けますが、書き方の柔軟性や制御構文(構文って呼ぶと怒られますが)が沢山ある感じとかはRubyっぽい雰囲気を感じます。僕はどちらの言語も好きなのでいい感じだとおもいます。

また、僕は言語仕様そのものよりもビルドの簡単さやエコシステムのほうを重視するタイプなんですが*1Clojureもleiningenというビルドツール兼色々とClojarというリポジトリのおかげでクッソ快適です。最高!

ちなみに今回のソースコードは以下みたいな感じです。

(ns shounin-clj.core
  (:require [clojure.tools.cli :refer [parse-opts]]
            [clojure.data.json :as json]
            [org.httpkit.client :as http]
            ))


(defn exit-with
  [st & funcs]
  (doseq [f funcs] (f))
  (System/exit st)
  )


(def shounin-options
  [
   ["-l" "--list" "list of vocabularies"
    :default false]
   ["-a" "--add WORD" "add a new vocabulary"]
   ["-d" "--delete INDEX" "delete a vocabulary"]
   ["-h" "--help"]])


(use '[clojure.string :only (join)])
(defn show-summary [options-summary]
  (->> ["API Client for 承認君(automatic shounin system)"
        ""
        "Usage: program-name [options]"
        ""
        "Options:"
        options-summary
        ]
       (join \newline)))


(defn get-vocabularies []
  (let [response1 (http/get "http://www.shounin.jp/vocabularies")]
    (for [vocabulary
          (get (json/read-str (:body @response1)) "vocabularies")]
      (when-not (= vocabulary nil) (format "%s: %s" (get vocabulary 0) (get vocabulary 1))))))


(defn add-new-vocabulary [word]
  (let [response (http/post "http://www.shounin.jp/vocabularies" {:form-params {:text word}})]
    (let [{:keys [body]} @response]
      (get (json/read-str body) "message"))))


(defn delete-vocabulary [index]
  (let [response (http/delete (str "http://www.shounin.jp/vocabularies/" index))]
    (let [{:keys [body]} @response]
      (get (json/read-str body) "message"))))


(defn -main [& args]
  (let [{:keys [options arguments errors summary]} (parse-opts args shounin-options)]
    (cond
      (= (count options) 0) (exit-with 1 (fn [] (println "no arguments")))
      (:help options) (exit-with 0 #(-> summary show-summary println))
      (:list options) (exit-with 0 #(println (join "\n" (get-vocabularies))))
      (:add options) (exit-with 0 #(println (add-new-vocabulary (:add options))))
      (:delete options) (exit-with 0 #(println (delete-vocabulary (:delete options))))
      )))

APIの量が少ないのもありますが、空行を入れても63行と大変短くらくちんでした。
たいしたコードではないですが、なんとなくClojureってこんな言語かーみたいな雰囲気はつかめるんじゃあないでしょうか。

というかclojure.tools.cliparse-optsめっちゃ簡単。Pythonコマンドラインパーサはクッソ大変なんだけど。

requestにはhttp-kitというサードパーティを使いました。こいつはpure Clojure(多分)で実装されている上、標準で並列リクエストやFuture, Promiseに対応していたりとめっちゃ高機能でAPIも使いやすいです。
この手のマイナー言語って、とにかくサードパーティの量と質がよろしくないイメージなんですけどClojureはコミュニティが濃いせいかどちらもすごい良い感じの印象です。

悪いところ

エラーメッセージがとにかく意味不明です。普及の妨げになるレベルだとおもいます。慣れとか霊感でなんとかするしかなさそうです。ファック!
javaの経験があれば少しは理解出来たりするのでしょうか……。今のところはJVM言語であることに対してメリットを(マイクラMODを書けること以外には)一切感じないです。

また、これは良いところでもあるのですが、高度な機能が多いので多人数だとついてこれない人が出てきそうです。関数型言語全般に言えることかもしれませんね……

標準ライブラリが貧弱なのが最初はすごい気になったのですが、これはコアをなるべく小さくしておこうとか、そういう文化なんですかね?
leiningenが使いやすい(準標準みたいなライブラリをこれでインストールする)のであまりストレスはないんですが、Battery includedな.NETやPythonみたいな言語でプログラミングを覚えた自分からするとこれはちょっと戸惑うところです。

まとめ

Clojureめっちゃ素敵なので、趣味でなんかやるときはしばらくClojure使います。

あ、ちなみに承認君クライアントcljはJavaなせいかクッソ起動遅いので普通にcurlAPI叩いた方が楽です。

以上です。

*1:例えばGo言語の素晴らしい所のひとつですね