defrecordで定義したデータを文字列化したときの内容はカスタマイズできるのでしょうか

投稿者: Anonymous clojure初心者です。 今日ようやくdefrecordのことを初めて知りました。深いことまでは分かりませんが、ふと思ったことがあります。 JavaであってもtoStringメソッドがクラスに定義されていればそのクラスオブジェクトに合った文字列表現を返すことができるように、clojureの場合も似たような仕組みはあるのでしょうか? 興味半分にdefrecordで定義したデータ型をstr関数に渡すと何かハッシュ値のようなものが出てきました。 user=> (defrecord abc [aiu xyz]) user.abc user=> (->abc 123 “ABC”) #user.abc{:aiu 123, :xyz “ABC”} user=> (str (->abc 123 “ABC”)) “[email protected]” この最後の部分を例えば”[abc: 123 xyz]”のような文字列表現に変えることはできるのでしょうか。もしかするとそんなことをしたらclojureの動作を破壊してしまうのかもしれませんが…… defrecordではない、ごく単純な例だとデータの内容がわかりやすく文字列化されているようです。 user=> (str #{1 2 3}) “#{1 3 2}” rubyなどではこの手の方法をデバッグで有効に使うこともあったので質問してみました。 今これがわからなくて困っているわけではないですが、後々のプログラミングで気になるようにも思うので、ご教示いただけると嬉しいです。よろしくお願いします。 ※ubuntu 15.04/windows7で、Clojure 1.8を使っています。 解決 質問のタイトルとズレはしますが、質問の意図からすると pr-str を使えば解決できる問題だと思います。また、シリアライズした結果を標準出力に出力する prn という関数もあります。 本当に望むのであれば次のような書き方もできます(が、多くの場合必要ないですし、推奨はしません)。 (defrecord Member [name age] java.lang.Object…(Continue Reading)

clojure で可変長引数をそのまま別の関数に引き渡す方法

投稿者: Anonymous 例えば可変長引数を要求する関数が2つあったとして、一方が他方を呼び出す関係にあるとします。 (defn abc [& args] (str (first args))) (defn aiu [& args] (abc args)) この場合、REPLで確認できた限りでは以下のようになりました。 user=> (abc “a”) “a” user=> (aiu “a”) “(“a”)” この例でいえば、関数aiuに渡された可変長引数をそのまま可変長引数として関数abcに渡す方法はあるのでしょうか? 何を言いたいのか分かりにくいのかもしれないので、別の例を挙げるとすると、具体的なイメージとしてはrubyのsplat演算子を使った例を思い浮かべています。 rubyでは引数にアスタリスク(*)をつけると、そこが可変長の引数を表す配列オブジェクトであることを示します。 def xyz(*args) args.each{|arg| p arg} end xyz(1,2,3) => 1 => 2 => 3 この例ではメソッドxyzは可変長の引数を受け取り、個々の引数を表示しています。 そこでclojureの例と同じように別の可変長引数を受け取るメソッドhogeを用意して、その中でxyzを呼び出したとします。 def hoge(*args) xyz(args) end hoge(1,2,3) => [1,2,3] 見ての通り、clojure同様、可変長引数は一旦配列オブジェクトとしてargsで表現され、それをそのままメソッドxyzに渡すと、配列を1個渡したとみなされます。 この挙動を変え、引数argsを再びxyzに可変長引数として渡すには、xyzに引数としてargsを渡す際にargsの前にアスタリスクをつけます。 def foo(*args) xyz(*args)…(Continue Reading)

compile + JAR化したclojureのプログラムが「java.lang.ClassNotFoundException: clojure.lang.Var」とエラーになる

投稿者: Anonymous Leiningenを使わず、clojureのREPL環境にてcompile関数を利用することでクラスファイルを生成し、それをjarファイルにまとめ、しかもjava -jar jarファイル名のような形で実行できるようにしたいと考えています。 javaについては言語の理解はありますが、それを支えるエコシステム(java, jarコマンド等)に関しては経験がなくて、リファレンスを見ながら試行錯誤している状態です。 このため、本件はclojureに関するミスがあってのことなのか、javaとそれに関するツールの使い方の問題であるかの切り分けが自分ではできませんでした。 ディレクトリ構成: 作業ディレクトリ(ルート)の下にサブディレクトリとして以下の名前のディレクトリを配置 classes test1 ルート直下にclojure-1.8.0.jar(clojureランタイム)を配置 test1ディレクトリの直下に core.clj を配置 core.clj: (ns test1.core (:gen-class)) (defn -main [greetee] (println (str “Hello ” greetee “!”))) REPL環境でコンパイル: $ java -cp ./clojure-1.8.0.jar clojure.main user=> (compile ‘test1.core) test1.core JARにまとめない形で実行してみる: $ java -cp ./classes:./clojure-1.8.0.jar test1.core Fred Hello Fred! JARファイルを作成: $ jar cfe test1.jar test1.core classes…(Continue Reading)

Clojureの関数で渡されたものと同じ型のコレクションを返すには?

投稿者: Anonymous 例えば次のような関数を定義したとして、渡されたコレクションと同じ型を返す良い方法はないでしょうか? ただし、評価値の順序がおかしくならないようにお願いします。 (defn rotate [n coll] (let [at (if (neg? n) (Math/abs n) (- (count coll) n)) [left right] (split-at at coll)] (concat right left))) こんなやりかたを考えてみましたが、ごちゃごちゃして気持ち悪いですよね。 何かシンプルな方法はないでしょうか? (defmulti vomit (fn [coll] (if (list? coll) :list (if (vector? coll) :vector))) :default nil) (defmethod vomit :list [coll] (partial apply list)) (defmethod vomit :vector [coll] (partial…(Continue Reading)

trampolineのデバッグ方法について

投稿者: Anonymous clojure 1.8 を使っています。 特にIDEなどは使っておらず、mifesやときどきvimでコードを書いておりまして、javaコマンドから直接REPL起動させ、実行結果を試しています。 純粋関数をなるべく多用することで大分デバッグが楽になったと感じているのですが、trampolineを使うときは引数に指定された関数が返してくる関数をさらに実行しながら進むので、動的に関数の実行順序や関数に渡すデータが変わっていきます。そういう状況ではprintlnくらいでしかデバッグの方法が分かりませんでした。 しかしこの方法は do 関数に println をいくつも書いたりしなくてはならなくなって、括弧の数も多くなりがちです。可読性が大分悪くなってしまいました。 もしきちんとプログラムを組むのであれば、こういう類をメンテナンスしていくのは正直辛くなってしまいそうです。しかしそんなことを多くの人が敢えて耐えているとも考えにくく。 そこで質問ですが、表題の通り、trampolineの動作をデバッグするのに効率の良い方法というのがあったら教えていただきたいです。よろしくお願いします。 解決 僕の回答はひとつの意見として参考までに受け取っていただけたらと思います。 結論から書くなら Cursive や CIDER の利用をまず最初に検討するべきです。 デバッグ環境が既に IDE やそれに準ずるプラグインなどで実装されているので、それらを利用すればこの問題は簡単に解決するでしょう。 参考までに CIDER でのデバッグ画面を貼っておきます。 例えば trampoline を利用する場合はこのようなコードに対して利用することになると思うのですが、何の問題もなくデバッグが可能です。 ただ、このような IDE やそれに準ずるプラグインを利用するのが、個人の主義に合わない場合もあると思います。その場合は書かれているように do マクロや print を駆使してデバッグするしかないでしょう。 あるいは相互再帰を利用して記述することが本当に綺麗な解法であるのか検討した方がいいのかもしれません。一般的なアプリケーションを書く場合、余程のことがない限り相互再帰で絶対に記述しなければならないというケースは稀有だと思います。 まとめると Cursive や CIDER などを利用しましょう 相互再帰で書かなればいけないのか見直しましょう というところでしょうか。 追記: spyscope という Leiningen や Boot で利用できるプラグインがあるので、これを利用するというのもひとつの手だと思います。 https://github.com/dgrnbrg/spyscope 回答者: Anonymous

`apply` を使った後に更に引数を渡したい

投稿者: Anonymous 例えば引数を3つ (一般にはn個) とる函数 (defn f [a b c] {:first a :second b :third c}) があったとして,[1 2] (一般には長さ m (≤ n) のリストっぽいもの) が別の函数から得られるので, それに加えてもうひとつ 3 (一般には n-m 個の引数たち) を適用して (f 1 2 3) の結果をえたい,というような状況を考えます. 例えば ((apply (partial partial f) [1 2]) 3) あるいは ((comp (partial apply f) conj) [2 3] 4) で所望の動作が得られるのですが,特に前者はなにをしているのかわかりづらすぎると感じます.函数の引数の途中までリストから渡したいということは稀にあるような気がします(ひょっとしてここが勘違い?).どうするのが適切でしょうか.(最近まで Haskell を触っていて…(Continue Reading)

restとnextの使い分けについて

投稿者: Anonymous 今読んでいる参考書(clojure in action)で以下の関数が例示してありました。 user=> (defn print-seq [s] (when (seq s) (prn (first s)) (recur (rest s)))) その本によると、この例ではseqで明示的にシーケンスの中身の有無をチェックしているので、recurの引数ではnextではなくrestを使うべきだと書かれていました。 restとnextについては以下のような違いがあります。 user=> (rest []) () user=> (rest nil) () user=> (next []) nil user=> (next nil) nil 見ての通り、restであれば引数のシーケンスが空だろうとnilだろうと空リストを返すという違いがあります。 一方、seqは引数でnilを受け取っても結局nilを返します。 user=> (seq []) nil user=> (seq nil) nil ここまで理解してみて、少し困ったことになりました。 ここまでの理解をそのままつなげると、上記の例では、関数の引数はnilであろうとシーケンスであろうと、どちらでも構わないように思われます。つまりrestをrecurの引数として積極的に推奨するほどの理由が分かりません。 user=> (print-seq nil) nil user=> (print-seq [])…(Continue Reading)

Clojureのライブラリとtools.reader

投稿者: Anonymous Clojure1.6と1.7のバージョン間互換についてです。 以下project.cljで依存ライブラリを指定しています。 :dependencies [[org.clojure/clojure “1.7.0-beta2”] [compojure “1.3.2”] [http-kit “2.1.16”] [ring/ring-core “1.3.2”] ;; <1> [ring/ring-defaults “0.1.4”] [org.clojure/clojurescript “0.0-3211”] ;; <2> [cljs-http “0.1.30”] [org.clojure/core.async “0.1.346.0-17112a-alpha”] [org.omcljs/om “0.8.8”]]  現状clojureにはstableなver.1.6とbetaの1.7がありますが、どうやらこの2つは内部のtools.readerに互換性がないようです。上の場合だと1.7依存のclojurescript<1>は動きますが、1.6依存のringサーバー<2>では「read関数に渡す引数の数が違う」という趣旨のエラーが出ます。  そこで、1.7のreaderを使うclojurescript<1>と1.6以前のライブラリ<2>において、それぞれ内部で使うtools.readerのバージョンを陽に指定する方法はないでしょうか。  もしくはもっと根本的に、1.6 – 1.7間のreader互換性の問題を解決できる方法はないでしょうか。 解決 まず、tools.readerはClojureの標準ライブラリではなく、独立したcontribライブラリなので、Clojureのバージョンが1.6なのか1.7なのかというのはここでは関係ありません。 ring-core 1.3.2が依存しているtools.readerのバージョン(0.8.1)とClojureScript 0.0-3211が依存しているバージョン(0.9.1)に互換性がないことが問題のようです。具体的にはエラーメッセージを見てみないと分からないですが、0.9.0でread-stringのアリティが新たに追加されているのでこれが原因と思われます。 対症療法としては以下の3つが考えられるでしょうか。 ClojureScriptのバージョンを0.0-3178に下げる ring-coreのバージョンを1.4.0-beta1に上げる [ring/ring-core “1.3.2” :exclusions [org.clojure/tools.reader]]する 1つめのClojureScriptのバージョンを下げる方法が一番無難だと思います。バージョンを0.0-3178まで下げると依存するtools.readerのバージョンが0.8.xになるのでread-stringのアリティの問題は解決されるはずです。ClojureScriptは現在、1週間に1回以上リビジョンが上がるようなペースで開発が進められています。特別な理由がなければ最新版を使う必要もないと思いますが、いかがでしょうか? 2つめは逆にring-coreのバージョンを上げることで、tools.readerのバージョンをClojureScriptに揃える方法です。ただし、1.4.0はまだbeta1が出たばかりという段階なのであまりお薦めはできません。 3つめは、使用するring-coreおよびClojureScriptのバージョンはそのままに、ring-coreからtools.readerをexcludeする方法です。ring-core内でtool.readerを使っているのはring.middleware.session.cookieだけのようなので、この名前空間を使わないのであれば問題なくexcludeできる可能性があります。 回答者: Anonymous

Clojureでリストからマップを作るには

投稿者: Anonymous キーと値のリストからマップを作りたいです。 ((:a 1) (:b 2)) このリストをマップにしたい。 {:a 1, :b 2} 以下のようにして結果は得られたのですが、もっとこう簡単に、またClojureらしい方法があるのではないかと思いました。 (apply merge (map #(apply assoc {} %) ‘((:a 1) (:b 2)))) よりよい方法があれば教えてください。 よりよいと考える理由も教えてください。 僕の方法がよくないのではないかと考える理由は効率です。リストの要素ごとにキーひとつだけのマップをまず作り、それからひとつのマップにまとめています。 解決 (into {} (for [[k v] ‘((:a 1) (:b 2))][k v])) とか? 回答者: Anonymous

clojureで「再代入できない」と言われる意図は何なのか

投稿者: Anonymous clojure初心者です。 非常に初歩的な質問ですみませんが、clojureといえども、varに対する再束縛は問題なくできると考えてよいのでしょうか? user => (def a 100) user => a ; 100と表示 user => (def a 200) user => a ; 200と表示 clojureが変数(varのこと)の参照先オブジェクトを変更できないイミュータブルな性質を持つことはjava等の経験から理解できます。 その一方で、関数型言語では「再代入」はできない、なんていう言葉も何度もそれとなく聞いておりまして、それはなんとなくそういうものなのかと思っていました。それゆえ、本日思わぬ形で上記の例に出会ってしまい、今までも似たようなものは見てたのでしょうが、はたと気がついて混乱しております。 私の拙い理解では、これだと再代入は「できている」、clojure流の言葉では「再束縛」が起きているとでも言えばいいのでしょうか、とにかく同じvarに別の値を結びつけることができています。 user=> (defn xyz [] (let [abc 100] (let [abc 200] (+ abc 100)))) user=> (xyz) 300 let を使っても同じことです。 変数の値の再代入は他の言語でも普通にありますし、この動作がおかしいなどと言うつもりは毛頭ないのですが、いわゆる「関数型言語に再代入はない」的な言説が何を言わんとしているのかがわからなくなりました。再代入ができないのではなく、再代入を避けやすい、という意味で使われることが多いのでしょうか。 「プログラミングclojure」という本を読みながら学習しているのですが、このことについては特に記述がないか、見つけられません。なので、しょーもない質問とは思いますが、おかしな理解をするのも良くないので、どなたか教えてくださると嬉しいです。 解決 defは、その名前空間のトップレベルのvar(≒グローバル変数)を新しく作ります。まあこれは例外ですね。現代的なプログラミング言語では、グローバル変数の変更はあまり重要ではありませんし。 letの入れ子の場合、「同じ名前だけど別の変数」を定義しているだけです。内側のletでabcに別の値を束縛しても、外側のletのabcは別の変数なので、影響を与えません。別の関数の仮引数の変数名が呼び出し元の変数名とカブっている場合(以下のコード片参照)とまったく同じです。 (defn foo [abc] (+ abc…(Continue Reading)

recurの引数に関して

投稿者: Anonymous 以下のコード、recurの部分で、期待してる引数の数と違う、とエラーが出ます。 recurの引数は式でなければならないのでしょうか? (defn prime [n] (let [result [] x 2] (when (and (zero? (rem n x)) (< x n))) (conj result x) (recur result (inc x)))) 解決 BLUEPIXYさんも言われているとおりですが、recurの引数の数が違っています。 本来、recurはloopと共に使われ、recurが呼び出されることで制御が(1番内側の)loopの位置まで戻ります。 (loop [x result [], x 2] … (recur (conj result x) (inc x))) …) 関数定義の先頭には、暗黙のloopがあるものとして扱われるので、対応するloopがない場合にはrecurの呼び出しは制御を関数の先頭まで戻します。挙げられている例のコードは以下と等価です: (defn prime [n] (loop [n n] (let [result []…(Continue Reading)

Clojureのsortシンボルに関して

投稿者: Anonymous CodeEvalのSimpleSortingの解法に関する質問です。 https://www.codeeval.com/open_challenges/91/ 以下のコードを実行すると、Float型のソートがうまく行きません。 (-10.000, -1.000, -2.000) -> (-1.000, -2.000, -10.000) なぜなのか、ヒントを教えてください。 (ns simple-sorting.core (:use [clojure.string :only [split join]]) (:gen-class)) (defn splt-num [s] (split s #” “)) (defn str->num [coll] (map read-string coll)) (defn num->float3 [coll] (vec (map #(format “%.3f” %1) coll))) (with-open [rdr (clojure.java.io/reader (first *command-line-args*))] (doseq [line (remove empty? (line-seq rdr))] (def…(Continue Reading)