Am Di., 15. Jan. 2019 um 14:58 Uhr schrieb <plamen.use...@gmail.com>:
> > Imagine I try on the one side to represent something like a database table > in memory, while on the other to make it pluggable into all meaningful > sequence and vector/map functions in Clojure. In the most naive > implementation a table is a vector of maps. If i would like to add more > functionality, while trying to remain transparent to Clojure functions I > could implement a custom Record type (IPersistentMap etc.) for the rows > (for a custom storage, for column ordering, type checking etc.) and this > works. I could also implement a custom Table (IPersistentVector etc.) for > the actual collection of records while maintaining internally some indexes, > the schema of the table etc. > IPersistentCollection and its derivatives are great to have on a custom data type, as applicable. To be a good citicen in modern clojure, you should also implement IReduceInit / IReduce. This allows your collection to drive a transducer stack, in order to evaluate whole-collection transformations at top-speed. All transducer machinery is based on IReduceInit, so as soon as you implement that, you enable efficient usage of reduce, transduce, into, eduction, ... on your collection. Also consider parameterizing your collection with a transducer stack, as a basis for composable, postponed-eager transformations: (table-transform #db{:trafo xf-db :db-data ...} xf-a) => #db{:trafo (comp xf-db xf-a) :db-data ...} The point is that if possible to apply let say (filter.. or (take 2 ..., > (sort .. incl. define/apply transducers. or whatever other Clojure function > compatible with these interfaces on the > Table/IPersistentVector/IPersistentCollection and get back a Table. > Implementing IEmptiableCollection allows the standard idiom: (into (empty db) xform db) If you have a more efficient way to transform your collection, e.g. by composing transducers, there is no direct Clojure interface for that, sorry. Though, you can implement something congruent to #(into (empty %1) %2 %1) and call it table-transform (traverse?). What I know: > 1. Clojure's doc actually says that sequence functions return sequences > and say nothing about preserving the original type, the implementations of > the sequence functions do actually as advertised and return usually Cons-es. > This is on purpose. As soon as you've called seq on something, you're not supposed to recover its original type and can only use more sequence functions on it. This allows for any number of intermediate sequence representations, most notably lazy-seq, but also chunked-seq, ... > 2. monads, yes, but the point is not to force the user to use custom > functions instead of the built in ones. > In short, Clojure being a dynamic language and hence not having type-guided expression generation (the return/pure problem), I think the best approach for implementing monads is to hardcode the continuation monad and embed other monads into that. See http://blog.sigfpe.com/2008/12/mother-of-all-monads.html#c6884748521935561127 That's what transducers essentially do, IMO. 5. I could attach table like descriptions to each Record object (be it in > its metadata or else), but then enforcing that all Records share the same > Table data could get penalizing at runtime. > That's the same trade-off as whether to implement substring by copying or pointing to the original string. I don't think there is a universal answer to that. Depends on your use case. So - do I miss something either in my knowledge or in the Clojure's > documentation/implementation and is there a meaningful way to apply > Clojure's and not mine filter/map/take/drop/sort etc. functions on a Table > and to get a Table back, without going the monads/own functions for > everything route or should I take it for granted that I can implement some > custom types, but no way to get them be fully transparent to Clojure? > As detailed above, clojure's seq abstraction is intentionally opaque, so own functions + implementing seq, empty, conj, being reducible and accepting transducers is as transparent as it gets. For optimizing single-thread performance, implement IEditableCollection For utilizing multiple cores, implement clojure.core.reducers/CollFold best regards -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.