2017-12-09 6 views
1

は、一例として、次のプログラムを取る:Clojureのエコープログラムを遅延無限シーケンスで構築できますか?

(defn echo-ints [] 
    (doseq [i (->> (BufferedReader. *in*) 
       (line-seq) 
       (map read-string) 
       (take-while integer?))] 
    (println i))) 

アイデアは、ユーザに入力を促し、それが整数だ場合、再度それをエコーすることです。しかし、この特定のプログラムでは、ほとんどすべての2番目の入力は即座にエコーされません。代わりに、2つの入力を同時に処理する前に、プログラムは追加の入力を待機します。
おそらく、これは何らかのパフォーマンスの悪循環の結果として起こります。しかし、この場合、私は本当に即座のフィードバックループが必要です。これを達成する簡単な方法はありますか、またはプログラムのロジックを大幅に変更する必要がありますか?
(ここでの主な動機は、遅延入力を他のレイジーシーケンスに変換する別の関数fにユーザ入力の無限シーケンスを渡すことです)。何らかのwhileループを書いた場合、私はfを使用できません。

+1

これはまた、(リード線) ''で起こっているのでしょうか? –

答えて

1

ほとんどのシーケンス関数には意図しない効果を引き起こすような組み込みの最適化が組み込まれているため、遅延効果と副作用(この場合は印刷)を混在させるのは一般的にうまくいかない。

はここで良いのライトアップです:https://stuartsierra.com/2015/08/25/clojure-donts-lazy-effects

何をしようとするcore.asyncチャンネルのために良いフィットのように思えます。私は、「無限のユーザ入力シーケンス」ではなく「ユーザ入力ストリーム」として問題を考えると、「遅延シーケンスを遅延シーケンスに変換する」は「ストリームを別のストリームに変換する」ようになります。これにより、fを自由に作成できるトランスデューサとして書くことができます。

-2

私は以下のようにします。いくつかの結果を表示するには、spyxspyxxfrom the Tupelo libraryを使用します。

(ns tst.demo.core 
    (:use tupelo.test) 
    (:require 
    [tupelo.core :as t]) 
    (:import [java.io BufferedReader StringReader])) 
(t/refer-tupelo) 

(def user-input 
"hello 
    there 
    and 
    a 
    1 
    and-a 
    2 
    and 
    a 
    3.14159 
    and-a 
    4 
    bye") 

(defn echo-ints 
    [str] 
    (let [lines (line-seq (BufferedReader. (StringReader. str))) 
     data (map read-string lines) 
     nums (filter integer? data) ] 
    (doseq [it data] 
     (spyxx it)) 
    (spyx nums))) 
(newline) 
(echo-ints user-input) 

これは私たちの結果を与える:

まず、缶詰の試験データとの簡易版を書く

it => <#clojure.lang.Symbol hello> 
it => <#clojure.lang.Symbol there> 
it => <#clojure.lang.Symbol and> 
it => <#clojure.lang.Symbol a> 
it => <#java.lang.Long 1> 
it => <#clojure.lang.Symbol and-a> 
it => <#java.lang.Long 2> 
it => <#clojure.lang.Symbol and> 
it => <#clojure.lang.Symbol a> 
it => <#java.lang.Double 3.14159> 
it => <#clojure.lang.Symbol and-a> 
it => <#java.lang.Long 4> 
it => <#clojure.lang.Symbol bye> 

nums => (1 2 4) 

だから、我々はそれが動作し、私たちがしたい数字を与えていることがわかります。

次に、ループバージョンを作成します。私たちはテストデータがなくなったときに正常終了させる。

(defn echo-ints-loop 
    [str] 
    (loop [lines (line-seq (BufferedReader. (StringReader. str)))] 
    (let [line  (first lines) 
      remaining (rest lines) 
      data  (read-string line)] 
     (when (integer? data) 
     (println "found:" data)) 
     (when (not-empty? remaining) 
     (recur remaining))))) 
(newline) 
(echo-ints-loop user-input) 

found: 1 
found: 2 
found: 4 

次に、キーボードを読み取る無限ループを作成します。あなたは、キーボードでCRTL-Cでこの1を終了する必要があります。

(ns demo.core 
    (:require [tupelo.core :as t]) 
    (:import [java.io BufferedReader StringReader])) 
(t/refer-tupelo) 


(defn echo-ints-inf 
    [] 
    (loop [lines (line-seq (BufferedReader. *in*))] 
    (let [line  (first lines) 
      remaining (rest lines) 
      data  (read-string line)] 
     (when (integer? data) 
     (println "found:" data)) 
     (when (not-empty? remaining) 
     (recur remaining))))) 

(defn -main [] 
    (println "main - enter") 
    (newline) 
    (echo-ints-inf)) 

をそして、我々はそれを手動で実行します。

~/clj > lein run 
main - enter 
hello 
there 
1 

found: 1 
and 
a 
2 
found: 2 
and-a 
3 
found: 3 
further more 
4 
found: 4 
^C 
                                             ~/clj > 
~/clj > 
関連する問題