0

Happens when I want to test a function where the result is another function. I have something like this:

ns flexsearch.core

(defn init [{:keys [tokenizer split indexer filter] :as options}]
  (let [encoder (get-encoder (:encoder options))]
    (assoc (merge {:ids {} :data {}} options)
           :indexer (get-indexer indexer)
           :encoder encoder
           :tokenizer (if (fn? tokenizer) tokenizer #(string/split % (or split #"\W+")))
           :filter (set (mapv encoder filter)))))

And in the test ns:

ns flexsearch.core-test
[flexsearch.core :as f]

(def split #"\W+")

(is (= (f/init {:tokenizer false :split split :indexer :forward :filter #{"and" "or"}})
         {:ids {},
          :data {},
          :tokenizer f/init/fn--14976,
          :split #"\W+",
          :indexer f/index-forward,
          :filter #{"or" "and"},
          :encoder f/encoder-icase}))

the result in the repl is:

{:ids {},
 :data {},
 :tokenizer #function[flexsearch.core/init/fn--14976],
 :split #"\W+",
 :indexer #function[flexsearch.core/index-forward],
 :filter #{"or" "and"},
 :encoder #function[flexsearch.core/encoder-icase]}

I know that I have to put f/index-forward instead of the result of the repl [flexsearch.core/index-forward], but it doesn't work with f/init/fn--14976 (No such var: f/init/fn--14976)

I supouse that is a trick with the vars but i dont know how it really works. Any reading you can provide i will be gratefull

---EDIT--- The f/index-forward and f/encoder-icase notations works fine.

---EDIT 2--- i've defined:

(defn spliter [split]   (fn [x] (string/split x (or split #"\W+"))))

and used it on:

(defn init [{:keys [tokenizer split indexer filter] :as options}]
  (let [encoder (get-encoder (:encoder options))]
    (assoc (merge {:ids {} :data {}} options)
           :indexer (get-indexer indexer)
           :encoder encoder
           :tokenizer (if (fn? tokenizer) tokenizer (spliter split))
           :filter (set (mapv encoder filter)))))

the I get a similar ":tokenizer #function[flexsearch.core/spliter/fn--34857]," that I used in the test and it also failed –

1 Answers1

0

I think the "No such var" error is happening because the tokenizer is an anonymous function.

If you had the default tokenizer defined as a non-anonymous function in flexsearch.core and then used that name in the test, it would work.

However, in general, you cannot compare two functions for equality - as @cfrick says. When you are comparing maps, where some of the values are functions, you are still comparing functions.

dorab
  • 807
  • 5
  • 13
  • what do you mean with cannot? that I shouldn't do that or that I cant? because (= + +) is indeed true.... sorry if my questions are silly – Fabricio Cozzarolo Sep 25 '20 at 03:45
  • 1
    You cannot. You can compare for identity, but not equality. Your example of `(= + +)` is an identity check. But the following is an equality check `(= (fn [x y] (+ x y)) (fn [x y] (+ x y)))`. In general, function equality is an undecidable problem. – dorab Sep 25 '20 at 16:30
  • Somehow, only the part of my comment went through. So, here is the rest.... In your edited example, each call to `(splitter split)` returns a **different** function. – dorab Sep 25 '20 at 16:42
  • As to your original error ("No such var"), in the REPL, the `#function[flexsearch.core/init/fn--14976]` that you are seeing is just how an anonymous (a function that is not bound to any name) is **printed**. `flexsearch.core/init/fn--14976`is not the name (i.e., symbol) that the function is bound to. So, when you specify `flexsearch.core/init/fn--14976` in the test, the system does not find any var bound to that symbol and so complains. You might find https://clojure.org/reference/vars and https://clojure.org/reference/evaluation helpful. – dorab Sep 25 '20 at 16:52
  • Specifically, when Clojure evaluates a symbol, it looks up the symbol in the namespace (which is basically a map from symbols to vars). The result of the lookup is expected to be a var. Then Clojure takes the contents of the var and uses that as the result of the evaluation. The following might be helpful https://clojure.org/guides/learn/syntax#_structure_vs_semantics - in particular, the paragraph that starts with "Most literal Clojure forms evaluate to themselves, except symbols and lists.". – dorab Sep 25 '20 at 17:00