How to use schema.core/enum in clojure? - clojure

Given an enum made from prismatic schema.core/enum, let's say:
(def myenumtype (schema.core/enum "a" "b" "c"))
How can I set another def to a specific enum item? Here I would like to set e to the "a" enum item.
(def e (??? myenumtype))
And how can I compare this to a specific enum? Here I would like to check to see if e is equal to the "a" enum type.
(= e ((??? "a") myenumtype))

I think you're misunderstanding how Schema works. You're not creating an enum type, you're creating a validator that checks if a particular value equals one of the enumerated values.
In your case, all you need to do is:
(def e "a")
Here's an example REPL session:
user=> (schema.core/validate (schema.core/enum "a" "b" "c") "a")
"a"
=> (schema.core/validate (schema.core/enum "a" "b" "c") "z")
clojure.lang.ExceptionInfo: Value does not match schema: (not (#{"a" "b" "c"} "z"))

Related

Failed to update a map with assoc in Clojure [duplicate]

This question already has answers here:
Why does (assoc-in everything ...) not change everything?
(2 answers)
Closed 2 months ago.
I have following map in my Clojure code:
typeList {"int" {"type" ["integer"]
"minimum" -2147483648
"maximum" 2147483647}
"bigint" {"type" ["integer"]
"minimum" -9223372036854775808
"maximum" 9223372036854775807}}
I am trying to add some new values to that map and I am using assoc key for that; however it seems it is not adding the new value since the println is not giving the new keyword.
For example, let's add "asd" to the map:
(assoc typeList "asd" {"type" ["integer"]})
However, when I try to print the new list, it returns as following:
(println typeList)
{int {type [integer], minimum -2147483648, maximum 2147483647}, bigint
{type [integer], minimum -9223372036854775808, maximum
9223372036854775807}}
Am I missing something? Couldn't figure that out since I am newbie in Clojure.
assoc will not change the existing value typeList, instead it returns a new value with the key "asd". In other words, typeList will be unchanged and the return value from assoc will contain the "asd" key.
Try this instead:
(def updatedTypeList (assoc typeList "asd" {"type" ["integer"]}))
(get typeList "asd")
;; => nil
(get updatedTypeList "asd")
;; => {"type" ["integer"]}

Easiest way to get an error message as a string in Instaparse?

Instaparse can pprint nice error messages to the REPL
=> (negative-lookahead-example "abaaaab")
Parse error at line 1, column 1:
abaaaab
^
Expected:
NOT "ab"
but I can not find a built-in function to get the message as a String. How to do that?
You could always wrap it using with-out-str:
(with-out-str
(negative-lookahead-example "abaaaab"))
You may also be interested in using with-err-str documented here.
(with-err-str
(negative-lookahead-example "abaaaab"))
I can't remember if instaparse writes to stdout or stderr, but one of those will do what you want.
Let's look at the return type of parse in the failure case:
(p/parse (p/parser "S = 'x'") "y")
=> Parse error at line 1, column 1:
y
^
Expected:
"x" (followed by end-of-string)
(class *1)
=> instaparse.gll.Failure
This pretty printing behavior is defined like this in Instaparse:
(defrecord Failure [index reason])
(defmethod clojure.core/print-method Failure [x writer]
(binding [*out* writer]
(fail/pprint-failure x)))
In the REPL this prints as a helpful human-readable description, but it can also be treated as a map:
(keys (p/parse (p/parser "S = 'x'") "y"))
=> (:index :reason :line :column :text)
(:reason (p/parse (p/parser "S = 'x'") "y"))
=> [{:tag :string, :expecting "x", :full true}]
And you could do this:
(with-out-str
(instaparse.failure/pprint-failure
(p/parse (p/parser "S = 'x'") "y")))
=> "Parse error at line 1, column 1:\ny\n^\nExpected:\n\"x\" (followed by end-of-string)\n"
Or write your own version of pprint-failure that builds a string instead of printing it.

Is there a way to use non Tuple objects with splat operator in Crystal?

Is there some function or syntax construction to make next examples work?
Invoke Hash#values_at function with an Array argument:
h = {"a" => 1, "b" => 2, "c" => 3}
ary = ["a", "b"]
h.values_at(*ary) # Error: argument to splat must be a tuple, not Array(String)
Pass Hash to initialize class or struct:
struct Point
def initialize(#x : Int32, #y : Int32)
end
end
h = {"x" => 1, "y" => 2}
Point.new(**h) # Error: argument to double splat must be a named tuple, not Hash(String, Int32)
The first example might be impossible, depending on the circumstances. However if the length of elements is fixed, you can do:
h = {"a" => 1, "b" => 2, "c" => 3}
ary = ["a", "b"]
p h.values_at(*{String, String}.from(ary))
https://carc.in/#/r/3oot See Tuple.from
NamedTuple supports the same approach:
struct Point
def initialize(#x : Int32, #y : Int32)
end
end
h = {"x" => 1, "y" => 2}
p Point.new(**{x: Int32, y: Int32}.from(h))
https://carc.in/#/r/3oov See NamedTuple.from
Both of these are just some sugar around ensuring types and decomposing the structure manually at runtime and mainly useful when your data comes from an external source, such as being parsed from JSON.
Of course it's preferred to create and use Tuple over Array and NamedTuple over Hash in the first place where possible.
Array and Hash are dynamically expanding containers, the number of elements can change at runtime and maybe the array might be empty when you try to splat it.
Tuple and NamedTuple consist of a fixed number of elements which is known at compile time so they can be used for splats. If the format of your data containers does not change, you can just use Tuple and NamedTuple instead.
ary = {"a", "b"}
h.values_at(*ary)

Check string length with variable in Clojure

I want a function written in Clojure that checks if my given String is bigger than my given number and if so, my function says true otherwise it says false.
Now i've come up with the following code, but it gives the following error:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/checker (form-init1692807253513002836.clj:1)
The code i've come up with is:
(defn checker [str, num]
(cond
(> (count str) num) "True"
:else "False"
)
)
(checker "test" 6)
Can someone explain why count str is considered as a Long and/or how this function can be fixed?
You might want to “fix” your function by considering some Clojure
idioms that apply to your snippet:
booleans are built in; no need to use "True"/"False" strings
(unless you’re just using these as a placeholder example for
something else)
don’t need to be explicit about the return booleans since >
already returns a boolean
you’re measuring “length” rather than “bigness”, so use a
descriptive function name; strlen is probably common
since boolean return value you can end with ?
probably avoid str as var name
switch the comparison order to use < instead of >, based on Elements of Clojure recommendation
With those in mind, your function simplifies down to:
(defn strlen-exceeds? [s n]
(< n (count s)))
(And now it’s short enough that you might not even need it to be an
explicit function.)
I think your code should work, but for this case, don't use cond use if.
(defn checker [str, num]
(if (> (count str) num)
"True"
"False"))
> (checker "a" 1)
"False"
> (checker "a" 2)
"False"
> (checker "ab" 2)
"False"
> (checker "ab" 2)

wrapping knockout.js using clojurescript

I'm trying to wrap knockout.js in clojurescript but its turning to be very difficult. The problem that I'm having is the reference to the 'this' variable. I'm thinking of giving up and just using javascript directly.
I've taken examples off http://knockoutjs.com/examples/helloWorld.html and http://knockoutjs.com/examples/contactsEditor.html
I've managed to wrap easy functions with some macros. For example:
var ViewModel = function() {
this.firstName = ko.observable("Bert");
this.lastName = ko.observable("Bertington");
this.fullName = ko.computed(function() {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
becomes:
(defviewmodel data
(observing :first_name "Bert")
(observing :last_name "Bertington")
(computing :name [:first_name :last_name]
(str :first_name " " :last_name)))
However, for something harder like:
var BetterListModel = function () {
this.itemToAdd = ko.observable("");
this.allItems = ko.observableArray(["Fries", "Eggs Benedict", "Ham", "Cheese"]); // Initial items
this.selectedItems = ko.observableArray(["Ham"]); // Initial selection
this.addItem = function () {
if ((this.itemToAdd() != "") && (this.allItems.indexOf(this.itemToAdd()) < 0)) // Prevent blanks and duplicates
this.allItems.push(this.itemToAdd());
this.itemToAdd(""); // Clear the text box
};
this.removeSelected = function () {
this.allItems.removeAll(this.selectedItems());
this.selectedItems([]); // Clear selection
};
this.sortItems = function() {
this.allItems.sort();
};
};
ko.applyBindings(new BetterListModel());
I'm not sure what I can do in clojurescript to match code like this: this.allItems.push(this.itemToAdd())
Any thoughts?
After lots of trial and error, I figured out how to have the same structure for clojurescript as for javascript.
The this-as macro has a few idiosyncrasies and only works when the method is put into the class
for example I want to create something that looks like this in javascript:
var anobj = {a: 9,
get_a: function(){return this.a;}};
I have to do a whole lot more coding to get the same object in clojurescript:
(def anobj (js-obj))
(def get_a (fn [] (this-as me (.-a me))))
(aset anobj "a" 9)
(aset anobj "get_a" get_a)
which is seriously ugly for a language as beautiful as clojure. Things get worse when you have got functions that link to each other, like what happens in knockout.
I found that the best way to create an js-object with lots of this's in there is to define a __init__ method, add it to the class and then run it, then remove it from the class. For example, if I wanted to make another object:
var avobj = {a: this,
b: 98,
c: this.a
get_a: function(){return str(this.a) + str(this.c);}};
written as clojurescript with and __init__ method looks like this:
(def avobj (js-obj))
(def av__init__
#(this-as this
(aset this "a" this)
(aset this "b" 9)
(aset this "c" (.-a this))
(aset this "get_a" (fn [] (str (.-a this) (.-c this))))))
(aset avobj "__init__" av__init__)
(. avobj __init__)
(js-delete stuff "__init__")
There's still a whole bunch more code than javascript... but the most important thing is that you get the same object as javascript. Setting all the variables using this form also allows the use of macros to simplify. So now I have defined a macro:
(defmacro defvar [name & body]
(list 'do
(list 'def name
(list 'map->js
{
:__init__
(list 'fn []
(list 'this-as 'this
(list 'aset 'this "a" "blah")))
}))
;(. js/console log ~name)
(list '. name '__init__)
(list 'js-delete name "__init__")))
and with map->js taken from jayq.utils:
(defn map->js [m]
(let [out (js-obj)]
(doseq [[k v] m]
(aset out (name k) v))
out))
Now I can write code like this:
(defvar avobj
a this
b 9
c (.-a this)
get_a (fn [] (str (.-a this) (.-c this))))
and for the answer to knockout:
(defvar name_model
first_name (observable "My")
last_name (observable "Name")
name (computed (fn [] (str (. this first_name) " " (. this last_name)))))
(. js/ko (applyBindings name_model));
Which is really nice for me as it matches javascript really well and its entirely readable!
If you need an explicit reference to JavaScript's this dynamic binding, ClojureScript provides a this-as macro:
https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/core.clj#L324