0
votes

I'm new to clojure and try to learn it by solving questions from https://www.4clojure.com. The task is to implement the flatten function. This is my implementation:

(ns clojure-noob.core                                                           
  (:gen-class))                                                                 

(defn -main                                                                     
  "I don't do a whole lot ... yet."                                             
  []                                                                            
  (= ((fn [coll]                                                                
        (let [flat (fn [coll]                                                   
                     (when-let [s (seq coll)]                                   
                       (if (sequential? (first s))                              
                         (concat (flat (first s)) (flat (rest s)))              
                         (cons (first s) (flat (rest s))))))]                   
          (flat coll)))                                                         
      '((1 2) 3 [4 [5 6]]))                                                     
     '(1 2 3 4 5 6))) 

When I run it in REPL like (-main) I get true.

When I run it as lein run I get this exception:

Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: flat in this context, compiling:(clojure_noob/core.clj:11:42) at clojure.lang.Compiler.analyze(Compiler.java:6688) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3766) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6870) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3834) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6870) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$IfExpr$Parser.parse(Compiler.java:2797) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6868) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6001) at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:6319) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6868) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6001) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6868) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$IfExpr$Parser.parse(Compiler.java:2797) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6868) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6001) at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:6319) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6868) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6001) at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5380) at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3972) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6866) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.access$300(Compiler.java:38) at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:6269) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6868) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6001) at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5380) at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3972) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6866) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3766) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6870) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$HostExpr$Parser.parse(Compiler.java:1009) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6868) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6863) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6001) at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5380) at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3972) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6866) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.access$300(Compiler.java:38) at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:589) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6868) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625) at clojure.lang.Compiler.eval(Compiler.java:6931) at clojure.lang.Compiler.load(Compiler.java:7379) at clojure.lang.RT.loadResourceScript(RT.java:372) at clojure.lang.RT.loadResourceScript(RT.java:363) at clojure.lang.RT.load(RT.java:453) at clojure.lang.RT.load(RT.java:419) at clojure.core$load$fn__5677.invoke(core.clj:5893) at clojure.core$load.invokeStatic(core.clj:5892) at clojure.core$load.doInvoke(core.clj:5876) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invokeStatic(core.clj:5697) at clojure.core$load_one.invoke(core.clj:5692) at clojure.core$load_lib$fn__5626.invoke(core.clj:5737) at clojure.core$load_lib.invokeStatic(core.clj:5736) at clojure.core$load_lib.doInvoke(core.clj:5717) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invokeStatic(core.clj:648) at clojure.core$load_libs.invokeStatic(core.clj:5774) at clojure.core$load_libs.doInvoke(core.clj:5758) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invokeStatic(core.clj:648) at clojure.core$require.invokeStatic(core.clj:5796) at clojure.core$require.doInvoke(core.clj:5796) at clojure.lang.RestFn.invoke(RestFn.java:408) at user$eval1036$fn__1038.invoke(form-init8418556840412273777.clj:1) at user$eval1036.invokeStatic(form-init8418556840412273777.clj:1) at user$eval1036.invoke(form-init8418556840412273777.clj:1) at clojure.lang.Compiler.eval(Compiler.java:6927) at clojure.lang.Compiler.eval(Compiler.java:6917) at clojure.lang.Compiler.load(Compiler.java:7379) at clojure.lang.Compiler.loadFile(Compiler.java:7317) at clojure.main$load_script.invokeStatic(main.clj:275) at clojure.main$init_opt.invokeStatic(main.clj:277) at clojure.main$init_opt.invoke(main.clj:277) at clojure.main$initialize.invokeStatic(main.clj:308) at clojure.main$null_opt.invokeStatic(main.clj:342) at clojure.main$null_opt.invoke(main.clj:339) at clojure.main$main.invokeStatic(main.clj:421) at clojure.main$main.doInvoke(main.clj:384) at clojure.lang.RestFn.invoke(RestFn.java:421) at clojure.lang.Var.invoke(Var.java:383) at clojure.lang.AFn.applyToHelper(AFn.java:156) at clojure.lang.Var.applyTo(Var.java:700) at clojure.main.main(main.java:37) Caused by: java.lang.RuntimeException: Unable to resolve symbol: flat in this context at clojure.lang.Util.runtimeException(Util.java:221) at clojure.lang.Compiler.resolveIn(Compiler.java:7164) at clojure.lang.Compiler.resolve(Compiler.java:7108) at clojure.lang.Compiler.analyzeSymbol(Compiler.java:7069) at clojure.lang.Compiler.analyze(Compiler.java:6648) ... 128 more

I suspect it has something to do with namespaces, but I have no idea how to solve it.

1

1 Answers

1
votes

Inside the let binding for flat, you refer to flat, which is not visible yet. There is an optional name argument to fn which you can use to resolve this issue.

(defn -main                                                                     
  "I don't do a whole lot ... yet."                                             
  []                                                                            
  (= ((fn [coll]                                                                
        (let [flat (fn flat [coll]                                              
                     (when-let [s (seq coll)]                                   
                       (if (sequential? (first s))                              
                         (concat (flat (first s)) (flat (rest s)))              
                         (cons (first s) (flat (rest s))))))]                   
          (flat coll)))                                                         
      '((1 2) 3 [4 [5 6]]))                                                     
     '(1 2 3 4 5 6))) 

Also, the code can be simplified significantly without changing the meaning:

(defn -main                                                                     
  "I don't do a whole lot ... yet."                                             
  []                                                                            
  (let [flat (fn flat [[el & els :as coll]]                                     
               (when coll                                                       
                 (if (sequential? el)                                           
                   (concat (flat el) (flat els))                                
                   (cons el (flat els)))))]                                     
    (= (flat [[1 2] 3 [4 [5 6]]])                                               
       [1 2 3 4 5 6])))