Closed joneshf closed 10 years ago
Much of this is going on in the formalize branch. However, I think it's getting too formal. Rather than this thing being a bi-everything, it should just be the singular version of everything. Primarily because it would be next to impossible to support things like filtering in a key-value way, unless we use the monad
. I feel this too over the top for something this simple. It should be able to be done with just foldable
, or maybe traversable
.
So the question to ask is, How do you represent each predicate
? For instance, when using map
, how should you get the values? I only see two possible ways: an array, or an object. With an array you might get it as [key, op, val]
or [op, key, val]
, with an object you might get it as {key: someKey, val: someVal, op: someOp}
.
So, if you wanted to uppercase all the values for some reason:
Array version
I = require \inquire
p = I.and (I.eq \cat \good), (I.ne \dog \bad)
p.map ([op, key, val]) -> [op, key, val.toUpperCase!]
Object version
I = require \inquire
p = I.and (I.eq \cat \good), (I.ne \dog \bad)
p.map ->
it.val .= toUpperCase!
it
There are issues with both. With the array style, you've got to remember the order of three things. Which might not seem like much, but I think that's the limit of what I want to care about. With the object style, you've got to work with objects, which in and of itself is less than fun. But it also forces us to expose the internals or an api wrapping the internals in order to work with it.
I'm leaning towards the array style, and having it be [op, key, val]
simply because I'm not sure how this will work out for not
and the whole WrapBool
, but I think it would make it easier to work with.
I think it'd be good to have some thoughts here. @taystack I think you deal with this most, so what would you suggest?
Actually, i think we have another option! Let a function like map
work only on the values, then give other implementations that work on the keys, or the whole shebangabang, like map-keys
, map-all
or whatever.
This way, users don't have to worry about unboxing arrays and stuff, and you can still write readable, simple code like:
I = require \inquire
p = (\cat `I.eq` \good) `I.and` (\dog `I.ne` \bad)
p.map (.toLocaleUpperCase!)
But if you want, or need, to go whole hog on the thing, you can still do that.
Honestly, I dig object notation. When coding in Livescript I tend to use dot notation when dealing with arrays anyways. Either way when I get what you dish out I'll just make it feel like an object. From a distance, it looks like it would be easier to access members of an object than indices of an array, but we're back to figuring out the lesser of two evils with that discussion.
So this is pretty much taken care of in https://github.com/concordusapps/inquire.js/tree/v0.4.0
It's a Functor
, so you get map
for just the values. It's a BiFunctor
so you get bimap
for the keys and the values. It's a Foldable
so you get foldr
and friends for the values, it's a BiFoldable
so you get bifoldr
and friends for the keys and the values. It's a Traversable
so you get traverse
and friends for the values. It's a BiTraversable
so you get bitraverse
and friends for the keys and values.
If you'd like more granularity, there's a Zipper
so you can traverse each element one at a time (or go directly to it if you know the exact path in the tree), modify it, then zip it back up and return the modified thing. We probably need a few more combinators for the Zipper
though in order to make it less boilerplate-y to work with, but the functionality is all there. I think something like findHole :: k -> InquireZ k v -> InquireZ k v
might be very helpful in this specific case.
The takeaway here is that now that we have Functor
, Foldable
, and Traversable
, we can do just about anything to this thing in terms of one of their primitives. We all know how powerful foldr
is, so we should also see how great these three things together are.
Recently ran into a case where I wanted to modify just one predicate. The way inquire is currently implemented would've required string parsing, and I'm not down with that. There should be some way to iterate what is returned, maybe even returning bits of the tree with a
find
method or something.