Search code examples
clojure

Clojure code, tinkering with :main


I'm trying to run the following code.

Below are the steps I took:

$ lein new app latinsq

I then modified project.clj as follows:

    (defproject latinsq "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :main latinsq.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

and /latinsq/src/latinsq/core.clj

(ns latinsq.core
  (:use [clojure.set :only (difference)]))


(defn replace-at
  "in string s, replaces character at index p with c"
  [s p c]
  (str
   (.substring s 0 p)
   c
   (.substring s (inc p))))

; memoized function to save time on sqrt calls
(def sqrt (memoize (fn [x] (Math/sqrt x))))


(defn candidates
  "assuming that the position pos is empty in sq, return those values that it might be"
  [pos sq]

  (let [sq-size (int (sqrt (count sq)))]

                    ; set difference between...
    (difference
                    ; ...all the possible values...
     (set (map #(first (str %)) (range 1 (inc sq-size))))

                    ; ...and the set of...
     (into #{}
       (concat
                    ; ...those in the same column...
        (map #(get sq %)
         (range (rem pos sq-size)
            (count sq)
            sq-size))
                    ; ...and those in the same row.
        (map #(get sq %)
         (map #(+ % (- pos (rem pos sq-size)))
              (range 0 sq-size))))))))




(defn latinsq
  "encode your partial-square as a string like 1--1
   this fn returns a lazy sequence of all solutions"
  [sq]
                    ; Find the first empty square
  (let [empty-pos (.indexOf sq "-")]

                    ; if none, we don't need to do anything
    (if (= -1 empty-pos)
      (list sq)

                    ; else make a lazy sequence of...
      (lazy-seq
                    ; ...the concatenation of all the results of...
       (apply concat
                    ; ...using "map" to recurse, filling in the empty
                    ; square with...
          (map #(latinsq (replace-at sq empty-pos %))

                    ; ...each possible value in turn
           (candidates empty-pos sq)))))))




;; So, now some examples

(time
 (latinsq "123------"))
;; "Elapsed time: 0.045368 msecs"
;; ("123231312" "123312231")

(time
 (latinsq "12---31--------4"))
;; "Elapsed time: 0.068511 msecs"
;; ("1243431224313124" "1243431234212134")


;; A bit harder, an empty 5x5 grid
;; has 161280 solutions according to
;; http://mathworld.wolfram.com/LatinSquare.html
(time
 (count (latinsq "-------------------------")))
;; "Elapsed time: 36980.759177 msecs"   <--- a bit slow
;; 161280


;; Having made sure that our function returns a lazy seq
;; the whole result can be treated lazily, so to find just one
;; solution to the 5x5 grid:
(time
 (first (latinsq "-------------------------")))
;; "Elapsed time: 0.985559 msecs"       <--- not slow
;; "1234521453345124523153124"

;; first 3 of 5524751496156892842531225600 solutions for a 9x9 grid
(time 
 (take 3 (latinsq "---------------------------------------------------------------------------------")))
;; "Elapsed time: 0.075874 msecs"
;; ("123456789214365897341278956432189675567891234658917342789523461896742513975634128"
;;  "123456789214365897341278956432189675567891234658917342789523461975634128896742513"
;;  "123456789214365897341278956432189675567891234658917342789524163896743521975632418")

I'm getting the following error:

Exception in thread "main" java.lang.Exception: Cannot find anything to run for: latinsq.core, compiling:(/tmp/form-init4810859530587029884.clj:1:73)
        at clojure.lang.Compiler.load(Compiler.java:7391)
        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.Exception: Cannot find anything to run for: latinsq.core
        at user$eval5.invokeStatic(form-init4810859530587029884.clj:1)
        at user$eval5.invoke(form-init4810859530587029884.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)
        ... 14 more

From the research I have done, the issue is caused by the name on :main. I've tinkered with this a few times and I have not been able to get this to work. Is this because "latinsq" is showing up too many times in the directory tree? Or, am I misunderstanding how to run the code.

Alternatively, when I finally get it to run, the only output is:

"Elapsed time: 0.468492 msecs"
"Elapsed time: 0.0796 msecs"

Solution

  • You forgot to define -main function - this one is automatically generated by leiningen in core namespace. You also didn't specify how you try to run the application, but I assume you just invoke lein run. As long as you add -main function to your namespace it should work. I also recommend wrapping the latinsq function invocations into another function to avoid evaluating them when namespace is loaded.

    Btw. this is the full output that I got (using unmodified -main generated by leiningen: lein run "Elapsed time: 0.183692 msecs" "Elapsed time: 0.055872 msecs" "Elapsed time: 68742.261628 msecs" "Elapsed time: 1.361745 msecs" "Elapsed time: 0.045366 msecs" Hello, World!