This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-01-27
Channels
- # alda (21)
- # announcements (7)
- # beginners (70)
- # boot (95)
- # braid-chat (28)
- # bristol-clojurians (2)
- # cider (22)
- # clara (4)
- # cljsjs (13)
- # cljsrn (40)
- # clojure (93)
- # clojure-argentina (1)
- # clojure-art (1)
- # clojure-miami (3)
- # clojure-norway (1)
- # clojure-portugal (2)
- # clojure-russia (39)
- # clojure-sg (3)
- # clojurescript (25)
- # clojurian-chat-app (4)
- # community-development (5)
- # conf-proposals (20)
- # cursive (48)
- # datomic (39)
- # devcards (5)
- # dirac (4)
- # editors (2)
- # events (11)
- # funcool (65)
- # hoplon (95)
- # jobs (12)
- # ldnclj (4)
- # lein-figwheel (2)
- # leiningen (1)
- # om (311)
- # onyx (20)
- # philosophy (4)
- # proton (41)
- # re-frame (83)
- # reagent (49)
- # ring-swagger (3)
- # spacemacs (8)
- # yada (5)
[ann] Initial work on arbitrary precision decimal type for clojurescript https://github.com/funcool/decimal
@niwinz: how do you deal when you need a type alias to implement some cats type abstraction on it? Do you just wrap that thing in a single field defrecord wrapper and implement it on that, or is there another way?
Oh, I figured you might be familiar with how Haskell names it since you implemented category theory library.
In Haskell you can take a type, say Map
and add a new type that is basically Map
but is nominally different from it NewMap
.
Yes, in this case, cats works in very similar way. It implements the abstraction as separated object that is late referenced to the final type
Basically I want to have a merging map semigroup - that is (mappend {:a {:b [1 2]}} {:a {:c "test" :b [3 2]}})
should result in {:a {:b [1 2 3 2] :c "test"}}
but I don't want to pollute Clojure types with this implementation, since it might be undesirable in other contexts.
My current idea is to have something like (ErrorContainer. {...})
that will implement a mappend
that recursively merges the contained value.
Before I was doing something like this:
(def alt-map-monoid
(reify
p/Context
(-get-level [_] ctx/+level-default+)
p/Semigroup
(-mappend [_ sv sv']
(merge-with
(fn [sv sv']
(if (clojure.core/and
(clojure.core/and (satisfies? p/Contextual sv)
(when-let [context (p/-get-context sv)]
(satisfies? p/Semigroup context)))
(clojure.core/and (satisfies? p/Contextual sv')
(when-let [context (p/-get-context sv')]
(satisfies? p/Semigroup context))))
(m/mappend sv sv')
sv'))
sv sv'))
p/Monoid
(-mempty [_]
{})))
(extend-type #?(:clj clojure.lang.PersistentHashMap
:cljs cljs.core.PersistentHashMap)
p/Contextual
(-get-context [_] alt-map-monoid))
So that's why I wanted to "newtype" the maps, so there can be some specific "validation maps" I can implement that for
I don't remember now, but I think that can be done in more simple way just parametrizing the current map context, without touching or implementing new context. Just let me remember that...
Furthermore if you are doing validation stuf, have you considered the validation type that comes with cats? http://funcool.github.io/cats/latest/#validation
As far as I can tell without that you will get only one error from validation, not all of them.
with validation you can get only one error per "field" , I guess you want collect more than one
so I think that if the current behavior does not fits for you needs, you should use something else
Basically I want (m/<*> (av/fail {:a [:wrong]}) (av/fail {:b [:wrong]}) (av/fail {:b [:more-wrong]}))
to "just work".
I just recommend take the validation code as initial code and modify it for you needs, it will result in much less hacks
The way I look at it (maybe I'm misunderstanding something) but given right mappend
definition validation would do what I expect:
(fail (let [sv (p/-extract sv)
sv' (p/-extract sv')]
(p/-mappend (p/-get-context sv) sv sv'))
yes, the way is creating a wrapper type that works like a map and implements a context with proper mappend impl for you
that should work, but it looks a little bit hacky IMHO, but if that is ok for you, it should work
(require '[cats.core :as m])
(require '[cats.builtin :as b])
(require '[cats.context :as ctx])
(require '[cats.protocols :as p])
(require '[cats.applicative.validation :as av])
(require '[clojure.set :as set])
(defrecord MyMap [v])
(def merge-context
(reify
p/Context
(-get-level [_] ctx/+level-default+)
p/Semigroup
(-mappend [_ sv sv']
(->MyMap
(merge-with set/union (:v sv) (:v sv'))))
p/Monoid
(-mempty [_]
{})))
(extend-type MyMap
p/Contextual
(-get-context [_]
merge-context))
(m/<*> (av/fail (->MyMap {:a [:wrong]})) (av/fail (->MyMap {:b [:wrong]})) (av/fail (->MyMap {:b [:more-wrong]})))
;; => #<Fail #user.MyMap{:v {:a [:wrong], :b [:wrong :more-wrong]}}>
Yeah, exactly what I wanted to implement, just wanted to know if you think it made sense. You didn't have to waste time writing that for me, I would have known how to do that - sorry. And thanks!
Don't worry, simply I think that it there was some other way to do so... and I want to experiment also