2009-10-07 6 views
5

la seguente espressione nella clojure funziona alla grande:Nullpointer in clojure durante l'esecuzione doseq con le espressioni multiple nel corpo

(doseq [x '(1 2 3 4)] (println x)) 

Questo mi dà una nullpointer:

(doseq [x '(1 2 3 4)] ((println x)(println "x"))) 

Si produce il seguente output:

user=> (doseq [x '(1 2 3 4)] ((println x)(println "x"))) 
1 
x 
java.lang.NullPointerException (NO_SOURCE_FILE:0) 
user=> (.printStackTrace *e) 
java.lang.NullPointerException (NO_SOURCE_FILE:0) 
    at clojure.lang.Compiler.eval(Compiler.java:4639) 
    at clojure.core$eval__5182.invoke(core.clj:1966) 
    at clojure.main$repl__7283$read_eval_print__7295.invoke(main.clj:180) 
    at clojure.main$repl__7283.doInvoke(main.clj:197) 
    at clojure.lang.RestFn.invoke(RestFn.java:426) 
    at clojure.main$repl_opt__7329.invoke(main.clj:251) 
    at clojure.main$legacy_repl__7354.invoke(main.clj:292) 
    at clojure.lang.Var.invoke(Var.java:359) 
    at clojure.main.legacy_repl(main.java:27) 
    at clojure.lang.Repl.main(Repl.java:20) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at jline.ConsoleRunner.main(ConsoleRunner.java:69) 
Caused by: java.lang.NullPointerException 
    at user$eval__266.invoke(NO_SOURCE_FILE:26) 
    at clojure.lang.Compiler.eval(Compiler.java:4623) 
    ... 14 more 
nil 

Basta aggiungere un set aggiuntivo di parentesi attorno al corpo di una doseq gi mi dice quel punto nullo. Cosa sto sbagliando?

+1

Ho capito come risolvere questo problema, ma non lo faccio davvero. Quando doseq esegue il suo corpo valuta le espressioni lì. ((println x) (println x)) Quanto sopra valuta un elenco con il valore di ritorno di println a testa (nil). Quindi, alla successiva iterazione, tenta di valutare quell'elenco. La soluzione è usare 'do'. (doseq [x '(1 2 3 4)] (do (println x) (println "x")))) –

risposta

10

Bene , hai già capito la soluzione, quindi solo alcuni suggerimenti per spiegare il comportamento:

In Clojure (proprio come in Lisp, Schema, ecc.) tutto è un'espressione e un'espressione è un atomo o una lista. Per quanto riguarda le liste, il manuale di Clojure dice

liste non vuote sono considerate chiamate per entrambi speciali forme, macro o funzioni. Una chiamata ha il formato (operandi operatore *).

Nel tuo esempio, il corpo ((println x) (println x)) è un elenco e l'operatore stesso è un'espressione che Clojure deve valutare per ottenere l'operatore attuale. Cioè, stai dicendo "valuta la prima espressione e prendi il suo valore di ritorno come una funzione per invocare la seconda espressione". Tuttavia, println restituisce, come hai notato, solo nil. Ciò porta allo NullPointerException se nil viene interpretato come operatore.

Il codice funziona con (do (println x) (println x)) perché do è un modulo speciale che valuta a turno ciascuna espressione e restituisce il valore dell'ultima espressione. Qui do è l'operatore e le espressioni con println ar gli operandi.

Per comprendere l'utilità di questo comportamento, si noti che le funzioni sono oggetti di prima classe in Clojure, ad esempio, è possibile restituire una funzione come risultato di un'altra funzione. Per esempio, prendete il seguente codice:

(doseq [x '(1 2 3 4)] ((if (x > 2) 
    (fn [x] (println (+ x 2))) 
    (fn [x] (println (* x 3)))) x)) 

Ecco, io sto in modo dinamico capire all'operatore di invocare su l'elemento della sequenza. Innanzitutto viene valutata l'espressione-if. Se x è più grande di due, i if evalutes alla funzione che stampa x + 2, altrimenti restituisce la funzione che consente di stampare x * 3. Questa funzione è applicata a x della sequenza.

5

Vedo che hai già capito il problema, tuttavia si prega di notare che non è necessario un fare:

(doseq [x '(1 2 3 4)] (println x) (println "x")) 

doseq è (come suggerisce il nome) un fare già :)

Problemi correlati