I'm trying to work on this one, I have a working solution, what I did was to create a module called Guard, and this module gets automatically required same as Kernel, Kernel.SpecialForms and Kernel.Typespecs.
But I have realized that there is a limitation, and is when the macros are not passed a variable, but a reference to it, let's say: kind = {:map, 1} is_kind(%{foo: :bar}, kind), is there trick to evaluate kind inside the macro that is valid in cond do is_atom(kind) -> quote do: .... is_tuple(kind) and is_atom(:erlang.element(1, kind)) -> quote do: ... but without putting the logic inside a quote (which will be invalid in a guard), and unquoting kind to get the value from its calling environment. thank you. On Sat, 13 Aug 2016 02:22:09 +0700 eksperimental <eksperimen...@autistici.org> wrote: > the Comparison group of kinds was the last group and I just included just to > see how much i could > push guard, > > But the rest of the groups are less controversial. > > - Basic and built-in types > - Additional: Derived from is_* functions > - Additional: Literal numbers > > and maybe it is arguable if we need them all of them, > - Additional: Convenience > > Would it be possible to have the best of both worlds here? > Allow users to define their own guards/kinds, and be able to call them from > is/are functions, and > offering a default set of kinds/guards like the ones listed above (or > whatever we agree are the > minimum needed to be supported by the language). > > defmodule DateTime > > defkind second(seconds) when seconds >= 0 and seconds <= 60 > > def new(..., seconds) when seconds is :second > > end > > The benefit of are* functions is that it reduces the amount in a significant > way when you have > several items on the left and several kinds on the right hand side. > > also having a defined list of default kinds, helps us to translate directly > from the typespecs > into guard definitions. > > On Fri, 12 Aug 2016 20:24:22 +0200 > José Valim <jose.va...@plataformatec.com.br> wrote: > > > > > > > thank you for your answer José, > > > > > > I can look into how we can add new kinds (I will need help with > > > defining how to deal with conflicting kinds). > > > I think the defguard approach is reasonable, but I thought it was > > > ditched for some reason. > > > > > > What we could do is create a defkind macro that uses defguard, but > > > creates kinds only (since defguard can create any kind of guard). > > > > > > > I think the concern runs a little bit deeper: if we have defkind, that is > > based on defguard, are they then like any other macro? Would we also manage > > importing and conflicts with import? If so, why don't we use them like any > > other macro? > > > > When reading your proposal, I effectively broke it two parts: > > > > 1. A huge collection of kinds, which could be implemented as macros. > > Imagine if we had is_mfa/1, is_list/2 and so on in the stdlib or on a > > Guards module. > > > > 2. A set of operators that easily apply a set of kinds (or macros) on the > > rhs to the lhs. > > > > Once we break it apart, I have the following feedback: > > > > 1. Instead of having a large collection of guards in the stdlib maybe we > > should make it easier to define your own guards since most times you can > > give it better names that are specific to your domain > > > > 2. What is the benefit of using "is/are" instead of multiple "and/or" > > calls? I am aware the former is more succinct but remember that if we have > > multiple and/or calls, then we can always create a new guard with defguard > > > > In other words, instead of having a general solution with a bunch of guards > > in the stdlib alongside some pre-defined combinations, I would prefer to > > have a composable solution that is built from small blocks because folks > > can extend it to their domain without forcing Elixir to add more kinds. > > > > Let me try to be more concrete. With the proposal above, I'd be tempted to > > write: > > > > defmodule DateTime > > def new(..., seconds) when seconds is [{:gte, 0}, {:lte, 60}] do > > > > > > But the best solution would most likely be: > > > > defmoduel DateTime > > > > defguard is_seconds(seconds) when seconds >= 0 and seconds <= 60 > > > > def new(..., seconds) when is_seconds(seconds) > > > > end > > > > > > Finally, I just want to say that, although I am not convinced on the "kind" > > mechanism, I love this proposal because it is asking the right questions > > and it makes me realize I could be writing better code. So thank you for > > that! > > > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/20170602072926.530696ae.eksperimental%40autistici.org. For more options, visit https://groups.google.com/d/optout.