2012-07-10 13 views
5

Pracuję w clojure przy użyciu klasy java, która zapewnia interfejs API pobierania dla pliku binarnego specyficznego dla domeny, przechowującego serię rekordów.Interop z clojure a z niestandardowym iteracyjnym interfejsem API Java

Klasa java jest inicjalizowana za pomocą pliku, a następnie zapewnia metodę .query, która zwraca instancję klasy wewnętrznej, która ma tylko jedną metodę .next, a zatem nie jest ładnie odtwarzana za pomocą zwykłego interfejsu API kolekcji Java. Ani klasa zewnętrzna, ani wewnętrzna nie implementuje żadnego interfejsu.

Metoda .query może zwrócić wartość null zamiast klasy wewnętrznej. Metoda .next zwraca ciąg rekordów lub wartość null, jeśli nie znaleziono żadnych dalszych rekordów, może zwrócić wartość null natychmiast po pierwszym wywołaniu.

Jak sprawić, aby ten interfejs API języka Java działał dobrze z poziomu aplikacji clojure bez pisania kolejnych klas java?

Najlepszym mogłem wymyślić jest:


(defn get-records 
    [file query-params] 
    (let [tr (JavaCustomFileReader. file)] 
    (if-let [inner-iter (.query tr query-params)] ; .query may return null                
     (loop [it inner-iter 
      results []] 
     (if-let [record (.next it)] 
     (recur it (conj results record)) 
     results)) 
     []))) 

To daje mi wektor wyników pracy z abstrakcjami clojure nast. Czy są inne sposoby na ujawnienie seqa z API java, czy to z Lazy-Seq czy z użyciem protokołów?

+0

To interesujące pytanie, ale co masz na myśli, mówiąc o niestandardowym interfejsie API języka Java? – octopusgrabbus

+0

@octopusgrabbus konkretnie mam na myśli kod Java nie zapewnia java.util.Iterator ani implementacji java.lang.Iterable. Logicznie kod java zapewnia iterację, ale bez połączenia ze standardowym interfejsem API. –

Odpowiedz

4

bez pomijania do lazy-seq:

(defn record-seq 
    [q] 
    (take-while (complement nil?) (repeatedly #(.next q)))) 

Zamiast (complement nil?) można też po prostu użyć identity jeśli .next nie zwraca logiczną false.

(defn record-seq 
    [q] 
    (take-while identity (repeatedly #(.next q)))) 

Chciałbym również trochę zrestrukturyzować punkty wejścia.

(defn query 
    [rdr params] 
    (when-let [q (.query rdr params)] 
    (record-seq q))) 

(defn query-file 
    [file params] 
    (with-open [rdr (JavaCustomFileReader. file)] 
    (doall (query rdr params)))) 
+0

ładne rozwiązania! – Gert

4

Twój kod nie jest leniwy, jak byłoby, gdybyś używał Iterable, ale możesz wypełnić lukę lazy-seq w następujący sposób.

(defn query-seq [q] 
    (lazy-seq 
    (when-let [val (.next q)] 
     (cons val (query-seq q))))) 

Może trzeba owinąć metodę zapytania, aby zabezpieczyć się przed pierwszą wartością zerową.

+2

Przesuń 'lazy-seq' w górę wokół' when-let'. –

4

Wydaje się to dobrym rozwiązaniem dla lazy-seq:

(defn query [file query] 
    (.query (JavaCustomFileReader. file) query)) 

(defn record-seq [query] 
    (when query 
    (when-let [v (.next query)] 
     (cons v (lazy-seq (record-seq query)))))) 

;; usage: 
(record-seq (query "filename" "query params")) 
Powiązane problemy