Given x and y, both designed to match a map with the same matching clauses. The only difference is in the order of the clauses:
(ns so.example
(:require
[clojure.core.match :refer [match]]))
(defn x [m]
(match m
{:a _} :a0
{:a _ :b _} :ab0))
(defn y [m]
(match m
{:a _ :b _} :ab0
{:a _} :a0))
I want to match {:a 1 :b 2}:
(x {:a 1 :b 2})
;=> :a0
(y {:a 1 :b 2})
;=> :ab0
The function y has produced the expected result for the given map.
Admittedly I may not understand how the algorithm works but I was under the impression that clojure.core.match would somehow work out that {:a _ :b _} is somewhat more specific than {:a _} and would therefore try that first.
Which is why I'm surprised to see that the order of the matching clauses seems to matter.
Why is that or what am I doing wrong?
The way the match calculates a pattern score can't discern {:a _} from {:a _ :b _}, which it probably should. What you can do instead, is to tell it specifically there is no :b in the map.
(m/match [{:a 1 :b 2}]
[({:a _} :only [:a])] :a0
[{:a _ :b _}] :ab0)
Related
from the sample code of core.match, url:https://github.com/clojure/core.match/wiki/Basic-usage
(let [x {:a 1 :b 1}]
(match [x]
[{:a _ :b 2}] :a0
[{:a 1 :b 1}] :a1
[{:c 3 :d _ :e 4}] :a2
:else nil))
;=> :a1
why we can just match a `x' ? any reason why we can't do that ?
(let [x {:a 1 :b 1}]
(match x
{:a _ :b 2} :a0
{:a 1 :b 1} :a1
{:c 3 :d _ :e 4} :a2
:else nil))
;=> :a1
You can; or at least that's what I'm inferring from reading the source and documentation of match.
The source of match starts with the lines:
(defmacro match
. . .
[vars & clauses]
(let [[vars clauses]
(if (vector? vars) ; If it's a vector...
[vars clauses] ; leave it alone,
[(vector vars) ; else wrap it in a vector
. . .]
The documentation also contains the bit:
. . . Optionally may take a single
var not wrapped in a vector, questions then need not be wrapped in a
vector.
So why are they showing examples with vectors? Likely for consistency of the syntax. That likely help comprehension in a simple, basic overview like that. Switching back and forth between using and not using a vector would necessitate explaining when a vector is necessary, and that would detract from the main point of the page.
Edit: Actually, it does explicitly explain on that page at the top that you can match on an unwrapped value. You can find it by searching for match x on that page.
I have the word describe, and I want to see how many times each letter appears in the word. Eg "e" appears twice, "d" appears once etc
I have tried
(for [letter (map str (seq describe))]
(count (re-seq letter describe)))
But I get the error
ClassCastException java.lang.String cannot be cast to java.util.regex.Pattern clojure.core/re-matcher (core.clj:4667)
Any help would be much appreciated
You can use frequencies to count the frequency at which each character appears in the string, returning a map like this:
(frequencies "ababacdefg")
=> {\a 3, \b 2, \c 1, \d 1, \e 1, \f 1, \g 1}
This works because the string is being treated as a sequence of characters. frequencies can be used on general collections:
(frequencies [1 1 2 3])
=> {1 2, 2 1, 3 1}
The key is the value being counted, and the value is the frequency.
In Scheme, I'm running (quote (+ 2 3)) returns (+ 2 3). From what I understood, the quote just told Scheme to not evaluate my expression for some purpose. I'm trying to make the list (+ 2 3) without the use of quote. So I tried:
Typed: (cons '+' (cons 2 (cons 3 '())))
Scheme's return:(+ cons 2 (cons 3 (quote ())))
- I don't understand why I got this return value. I was hoping for (+ 2 3)
Typed: (cons '+' (2,3))
Scheme's return:(+ 2 3)
- I don't understand how this worked. So, is (cons '+' (2,3)) the same as (quote (+ 2 3))?
'expression is the same a (quote expression) and it becomes expression unevaluated.
When you write (cons '+ '(cons 2 (cons 3 '()))) you are quoting both + and the second argument, (cons 2 (cons 3 '())). The ' has no end marker.
When displaying pairs a Lisp system will default to displaying pairs with a pair tail as a list if you wondered why it didn't turn into (+ . (cons 2 (cons 3 (quote ()))))
An implementation can choose how to display '(quote ()) and ''(). Mine show '() while yours show (quote ()). They represent the exact same so it's not really different in other things than the visualization.
`(1 , 2) is the same as (list '1 2) since you are unquoting 2. Luckily for you it's a number and it always evaluates to itself. It might be that you though the comma was some sort of separation between elements, but it's not. It's just to simplify writing a large data structure where only a few elements are variable.
(define (test e)
`(a list with ,e representing some wanted structure))
(test 'test) ; ==> (a list with test representing some wanted structure)
I'm stuck trying to write a Clojure function that takes a span from a collection or vector.
For example I'd like to manipulate a collection such as
(:a :b :c :d :e :f :g :h)
by taking the second element through the fifth in steps of two.
Thus, outputting
(:b :d).
If you haven't figured it out by now, here is a function that does what you want.
(defn take-span
[start end step coll]
(take-nth step (take (- end start) (drop start coll))))
(take-span 1 4 2 '(:a :b :c :d :e :f :g :h))
Hope this helps!
Have a look at (take-nth n coll) function
(take-nth n coll)
Returns a lazy seq of every nth item in coll.
user=> (take-nth 2 (range 10))
(0 2 4 6 8)
It is not an exact match for your question but it is a good starting point for inspiration.
Of course, you can check the source code via:
(source take-nth)
How would I get something similar to the following?:
(evaluate-text "(+ 1 2)") ; resolves to 3
(load-string "(+ 1 2)")
user> (eval (read-string "(+ 1 2)"))
3
You probably shouldn't ever need to do this. Macros and fns make this kind of thing unnecessary 99% of the time. This is quite brittle, and can be unsafe if these strings are coming from user input, and so on.
How similar does it have to be? Clojure's eval works on lists, so:
(eval (list + 1 2)) #=> 3