Guten-tag looks pretty great. I think your readme also explains the 
differences pretty well.

I definitely feel like variants are really not great as data-structures to 
manipulate, but much better as declarative data constructors. Your library 
kinda unifies both into one type, its pretty clever.

On Monday, 28 August 2017 13:53:33 UTC-7, Reid McKenzie wrote:
>
> FWIW I wrote a library around defining tagged map types 
> https://github.com/arrdem/guten-tag and used it heavily in the Grimoire 
> implementation almost entirely to my satisfaction. No idea if anyone else 
> ever picked it up, and due to implementation details of Clojure's let map 
> destructuring you can't just treat one of my map wrapper types as a normal 
> Clojure map and :keys it apart but it works great with core.match.
>
> Reid
>
> On Friday, August 25, 2017 at 1:30:37 PM UTC-7, tbc++ wrote:
>>
>> >> they're a little nicer to type and read
>>
>> And that's where I have to disagree. The problem with most of these 
>> options is they complect ordering with meaning. 
>>
>> [:image/file "/images/image" :jpeg]
>>
>> Here I have no idea what these values mean. I have to have out-of-band 
>> information about what offset in the vector corresponds to what value. 
>> Functions have this same problem, look no further than `cons` vs `conj` to 
>> see potential confusion on argument ordering. 
>>
>> So why don't we only use maps for function arguments? Well mostly to make 
>> the functions easier to manipulate by humans. But some of the best 
>> libraries for web APIs (AWS) that I've used have used almost an exclusively 
>> map based interface. 
>>
>> Once again I have to repeat my mantra about DSLs. Don't start with DSLs. 
>> Start with maps. Build everything off of maps. They're extensible, easy to 
>> introspect, and can drive a host of metaprogramming algorithms. If maps are 
>> to hard to understand, build constructor functions on top of them. Then 
>> finally build a DSL on top, if you need it. 
>>
>> Frankly, I have so many things I have to remember during programming. I'd 
>> much rather see a very uniform map-based interface. Than any sort of nested 
>> vectors, tagged values, or anything else. 
>>
>> Surely we can't say that this:
>> >> [[:image/file :image/web] :image.file/path "/images/image" 
>> :image.file/format :jpeg :image.web/url "www.myimage.com/image"]
>>
>> Is a better interface than:
>>
>> {:image.file/path "/images/image"
>>  :image.file/format :jpeg
>>  :image.web/url "www.myimage.com/image"}
>>
>> And as I said before, spec is designed from the start to support data in 
>> this format. Stating "this is a file", "this is a web image". Is just book 
>> keeping that doesn't need to be done. Is a map a :image/web? Well check its 
>> members and see if they match the spec. If they match, then you have a 
>> :image/web. No need for sum types, tags, wrapping values in vectors. Simply 
>> state what a thing should have for it to conform to an interface, and 
>> forget whatever else might be in there. It couldn't be simpler. 
>>
>> On Fri, Aug 25, 2017 at 11:59 AM, Didier <did...@gmail.com> wrote:
>>
>>> Thanks for everyone's great input.
>>>
>>> Currently, I see the big distinction being concise vs extension. Maybe 
>>> for streaming variants would be better as the format would be smaller to 
>>> transfer over a wire. And for small short lived programs, or things you 
>>> know won't need extension, variants offer a slightly more convenient 
>>> structure to work with.
>>>
>>> I think both can be specced easily. S/or a few s/tuple to spec a 
>>> variant. And multi-spec over a set for the map version.
>>>
>>> I'd like to explore then the issue of extensibility with variants. How 
>>> would you extend them, is there really no way? This is some of my 
>>> brainstorming thoughts.
>>>
>>> 1) How to design a variant of more then one value?
>>>
>>>
>>> 1.1)
>>>
>>> I know this is a standard variant of one value:
>>>
>>> [:image/web "www.myimage.com/image.jpg"]
>>>
>>> I believe to extend it to more values, you would do:
>>>
>>> [:image/file "/images/image" :jpeg]
>>>
>>> That is, you'd threat it as a constructor function, which creates an 
>>> :image/file type and takes an ordered list of arguments. This way, each 
>>> variant type can even be overloaded on their arguments the way you'd 
>>> overload a function.
>>>
>>> [:image/file "/images/image"]
>>>
>>> Can default to format :png for example, when using the one arg 
>>> constructor.
>>>
>>> 1.2)
>>>
>>> An alternative is to keep variants as vector pairs, and nest them.
>>>
>>> [:image/file [:image/file-path "/images/image"] 
>>> [:image/file-format:jpeg]]
>>>
>>> In this form, variants are more like their map counterpart. Each element 
>>> is named and itself a variant.
>>>
>>> 1.3)
>>>
>>> You could also decide to limit variants to strict pairs, so the second 
>>> element of any variant is either a variant or a vector of variants.
>>>
>>> [:image/file [[:image/file-path "/images/image"] 
>>> [:image/file-format:jpeg]]]
>>>
>>> Now with both these forms, 1.2 and 1.3, if you threat them again as 
>>> constructor functions, you now have a form of named parameter on your 
>>> constructor, allowing mixed order.
>>>
>>> 1.4)
>>>
>>> At this point, the variant has become pretty similar to a map, losing in 
>>> verbosity over it even. There's just one advantage, the type is not a 
>>> key/value pair, which I find is more intuitive to use, no need to know the 
>>> special name of key that holds the type.
>>>
>>> 1.5)
>>>
>>> Let's try to make it concise again.
>>>
>>> [:image/file {:image/file-path "/images/image" :image/format :jpeg}]
>>>
>>> This hybrid avoids needing a type key, while having named parameters, 
>>> its the best of both worlds, but it mixes vectors and maps.
>>>
>>> 1.6)
>>>
>>> Here it is with the lispcast suggestion:
>>>
>>> {:image/file {:image/file-path "/images/image" :image/format :jpeg}}
>>>
>>> What I don't like about this, is how do you group variants together? Do 
>>> you add more to this map? Do you keep each variant a map of one key and 
>>> group them on a vector?
>>>
>>> It does solve the problem of wanting to pass a vector to your variant 
>>> though, as the lispcast blog talks about.
>>>
>>> 1.7)
>>>
>>> So I'm left with this form, which Clojure macros and options often use:
>>>
>>> [:image/file :image/file-path "/images/image" :image/format :jpeg]
>>>
>>> This is harder to spec I think, but you could write a predicate that 
>>> did, there's just not an existing one that can do it I think.
>>>
>>> Now a variant is a tuple with first element being the type, and an 
>>> alternating pair of key/values. This is extensible like map, yet more 
>>> concise. It isn't ambiguous to pass in a vector either, and lets you have 
>>> names while not enforcing order.
>>>
>>> Now what if I'd want the option to create my variant with named 
>>> parameters or not? Some languages allow for powerful constructors like that.
>>>
>>> 1.8)
>>>
>>> To do that, you need a way to distinguish if the rest of the vector is 
>>> an alternating of named pairs, or an ordered list of arguments. I'm stuck 
>>> here, I'm not sure its possible without restricting the typed a variant can 
>>> take. If you group the rest in a vector or a map to indicate named pairs, 
>>> then you can no longer pass a vector or map argument to a variant, since 
>>> they'll be interpreted as a named pair list. You could use meta maybe, or a 
>>> reader tag? Not sure I like those ideas though.
>>>
>>>
>>> 1.conclusion)
>>>
>>> I like 1.1 and 1.7 the best.
>>>
>>> I find 1.7 might actually be a better alternative to using maps. Its 
>>> more intuitive, looks like a type constructor, but just like maps it allows 
>>> arbitrary order and has names for readability while being more concise. 
>>> Best of both worlds. Its not ambiguous either, you can easily pass in 
>>> vector arguments.
>>>
>>> 1.1 is also great, if you don't mind losing named parameters and having 
>>> implicit ordering. Its also non ambiguous, very concise and allows 
>>> overloading.
>>>
>>> Now, that's when you use them as type constructors. But the "type" you 
>>> construct from them, after parsing the variant might be best represented as 
>>> a Clojure map or record. It would be annoying to use a variant like that as 
>>> an actual datastructure to perform logic on. If you need to get the 
>>> :image/format value in a lot of places, you probably don't want to be 
>>> passing around the variant and perform linear search lookup for it, and you 
>>> can't use any of Clojure's function to modify the variant. You could 
>>> implement some I guess, like an update-variant. So given this fact,  using 
>>> maps have an advantage that they're more homoiconic, you don't need to 
>>> parse them, when you construct them the result is not a type constructor, 
>>> but the actual datastructure you'd want to work with.
>>>
>>> 2) What can you use them for?
>>>
>>> 2.1) As pseudo type constructor they work well. For cases where the type 
>>> is constructed by hand, they're a nice DSL. I find they make sense then for 
>>> hiccup for example. When your types are constrcuted by the computer, I 
>>> think maps are better. No need to parse them. It would be cool maybe to 
>>> deftype an actual variant type. In a way, defrecords are almost that.
>>>
>>> 2.2) As open sum types. When something expects a variant, it means that 
>>> thing can be one of any variant type. With namespaced keys, they can be 
>>> restricted to a smaller open set. So :image/... variants are the set of 
>>> open image variants. Something can spec that it takes a variant whose 
>>> namespace is image. Then you're free to extend image variants with more of 
>>> them, like image/web, image/file, etc.
>>>
>>> 2.3) As closed sum types. I guess you could also spec something to 
>>> accept a specific set of specific variants, like either a :success or a 
>>> :failure variant.
>>>
>>> 2.4) They could be used as product types too. Just allow the type 
>>> argument to be a vector.
>>>
>>> [[:image/file :image/web] "/images/image" :jpeg "www.myimage.com/image"]
>>>
>>> This gets harder to oberload arguments though. Unless you use the named 
>>> pair version.
>>>
>>> [[:image/file :image/web] :image.file/path "/images/image" 
>>> :image.file/format :jpeg :image.web/url "www.myimage.com/image"]
>>>
>>> 2.conclusion)
>>>
>>> I can see now how Jeanine was saying you can use them as the foundation 
>>> for types of a programming language. Personally, I'll explore they're use 
>>> when I'm coming up with DSLs, or any time I need to manually create types, 
>>> I might use variants to construct them, even if what I'm constructing is a 
>>> map, they're a little nicer to type and read.
>>>
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups "Clojure" group.
>>> To post to this group, send email to clo...@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+u...@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+u...@googlegroups.com.
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>
>>
>> -- 
>> “One of the main causes of the fall of the Roman Empire was that–lacking 
>> zero–they had no way to indicate successful termination of their C 
>> programs.”
>> (Robert Firth) 
>>
>

-- 
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.

Reply via email to