Open marick opened 4 years ago
There's a delicate balance to find, I think, between doing what specter does and doing what's natural to erlang/elixir. One thing we don't do in elixir is support tuples the same way we support lists, because tuples are a bit shit, frankly.
MapKey requires a parameter, the key to look up, so you'd use it like {MapKey, :a}
. Were you looking for MapKeys (access the keys of the map)? This is another attempt to balance 'being elixir' with 'being specter'. MapKeys
takes 0 args, because there is nothing to parameterise it with. You could pass a dummy argument by tupling it, but it would just get dropped. This structure is designed so that one day we could compile it with macros, should I ever get around to such a thing.
I am strongly considering adding some "works on just about anything" options, where e.g. you can treat a list as an index-keyed associative structure as well as work on keyword lists and maps, but i thought for the first cut it would be better to give people the ones that do type checks.
Argument ordering thing makes sense, I just did what specter did without thinking and that can easily be changed.
Atoms as navigators is a little controversial, which is why I haven't yet experimented with it. Module names are of course atoms, too, and the reason why keywords work in clojure is because they're functions, which they aren't in elixir. Not sure what to do there to be honest.
agree on aliases, there should be a better option there.
Did I miss anything? Thanks for the feedback!
MapKey requires a parameter, the key to look up, so you'd use it like {MapKey, :a}
That doesn't work either:
iex(3)> select [{MapKey, :a}, {Elem, 0}], %{a: {0, 1}}
** (UndefinedFunctionError) function Banshee.MapKey.a/2 is undefined or private
(banshee 0.1.0) Banshee.MapKey.a([{Elem, 0}], %{a: {0, 1}})
but i thought for the first cut it would be better to give people the ones that do type checks.
My guess would be that the effort of writing syntax like {MapKey, :a}
will limit the number of people who will try the library. So I wouldn't publicize it until there's some syntactic sugar, however sweet you decide it should be.
Atoms as navigators is a little controversial, which is why I haven't yet experimented with it.
With whom? They're used that way in put_in
.
Did I miss anything? Thanks for the feedback!
I think I want to re-emphasize this:
There probably needs to be a "Why is this better than get-in and friends?" Less cumbersome for arrays and structs? Has navigators like LAST? Etc.
For Specter, ALL
alone speaks to a killer use case that what's built into Clojure doesn't satisfy. But there's an Access.all
in Elixir Kernel, so there needs to be an equivalent "wow!" feature for Banshee.
I was hoping the same path would work for lists and tuples, but alas:
I believe the way to access a map is supposed to be like this:
But that fails because there's no
MapKey.select/2
:I suspect that's a bug and
MapKey.select/3
should be called. The following works:If I'm right about the API, I wonder why the syntax for
Elem
andMapKey
is different. Having one be{Elem, 0}
and the other beMapKey, :a
seems odd.Unless I'm missing something, there's not a single
import
oralias
that pulls in all the special words. You have to do something like:That may make Banshee not pass the "impatience test" of wanting to see something neat really quickly.
I also notice that relying on aliases makes for rather confusing error messages. I somehow mindlessly started copy-and-pasting the nonexistent
MapVal
instead ofMapKey
, and became bewildered.Even after I realized it was the wrong module name and started using
MapKey
, I was still confused because I hadn't aliasedBanshee.MapKey
.I would flip the order of arguments to put collection argument first, the way it usually is in Elixir. (I know the Spectre author has a reason for putting the collection last, but I forget what it is. In any case, Clojure has both "pipe value into first position" and "pipe value into last position" pipe operators, but Elixir only has the first. That makes deviating from convention a harder sell.)
All that given, may I suggest a layer of syntactic sugar over the module-based implementation?, so that you can do this...
And add on syntactic sugar that says a bare atom means get the corresponding value in a
Map
or struct. And that a number works for any indexable thing - array, tuple, range, stream.(KEYS and VALS should work for both maps and keyword lists, which is why I dropped the "Map".)
I would probably have atom notation work with structs out of the box, though I don't know how strongly people would react to a deviation from José's design principle. I hope the Elixir community is more like the Ruby community in my active days (2001 to maybe 2007) than it is like the redacted and redacted communities.
(I haven't thought about the way to add syntactic sugar for user-defined navigators.)
There probably needs to be a "Why is this better than
get-in
and friends?" Less cumbersome for arrays and structs? Has navigators like LAST? Etc.