2017-01-12 5 views
1

ユーザの設定に基づいて関数節を動的に生成する必要があります。動的に関数節を生成する

@atoms ~w|foo bar baz|a 

config.exs、たとえば、から:明確にするために、私はアトムのリストを持っている想像してみてください。私に必要なのは(MCVEが単純化が、それは私が実際に必要なものに印象を与えている)、この関数を生成することです:

@checker fn 
    {:foo, _} -> false 
    {:bar, _} -> false 
    {:baz, _} -> false 
    _ -> true 
end 

私が現在やっていることは次のとおりです。

@clauses Enum.map(@atoms, fn tag -> 
    {:->, [], [[{:{}, [], [tag, {:_, [], Elixir}]}], false]} 
end) ++ [{:->, [], [[{:_, [], Elixir}], true]}] 

defmacrop checker, do: {:fn, [], @clauses} 

それはかなり動作しますしかし、私は何かを単純に欠けて、ものを過度に複製していると思う。だから私の質問は:

コンパイル時に関数節を生成する簡単な方法はありますか?

+0

コンパイル時に関数節を生成する良い例は、次のとおりです。https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/base.ex lines 95-114 –

+0

@DavidWhitlockこれは、トップレベル_に多くの関数宣言を生成する例ですが、私が求めていることとは何の関係もありません。私は別の 'def'sを生成することに問題はありません。 – mudasobwa

答えて

2

私はquoteを使用して、より読みやすい(詳細については下記を参照)、ややそれを作った:

defmodule A do 
    @atoms ~w|foo bar baz|a 
    @clauses Enum.flat_map(@atoms, fn tag -> 
    quote do: ({unquote(tag), _} -> false) 
    end) ++ quote(do: (_ -> true)) 

    defmacro checker, do: {:fn, [], @clauses} 
end 

defmodule B do 
    require A 
    f = A.checker 
    IO.inspect f.({:foo, :ok}) 
    IO.inspect f.({:bar, :ok}) 
    IO.inspect f.({:baz, :ok}) 
    IO.inspect f.({:quux, :ok}) 
end 

出力:

false 
false 
false 
true 

を私は仕事にquote(do: a -> b)を期待し、それはパースエラーです今すぐリストの中に望む引用されたフラグメントをラップするquote(do: (a -> b))を実行する必要があります。

quoteの場合はfnの内部で動作するとも期待していましたが、それもありません。

iex(1)> quote do 
...(1)> fn 
...(1)>  unquote() 
...(1)>  _ -> true 
...(1)> end 
...(1)> end 
** (SyntaxError) iex:2: expected clauses to be defined with -> inside: 'fn' 

私はこれらの2つがバグであるか、欠落していると考えています。

+0

'quote(do:(a - > b))' wow :)私は 'quote(do:a - > b)'を試して、あきらめました。私も引用符で囲まれたコードの中でunquotingを試みましたが、間違った優先順位があります(構文チェック_before_ 'unquote')。はい、これは少し読みやすくなりますが、私はもっと魔法の答えを待っています。 Upvoted、2日+賞金+ 1週間後に受け入れます。 – mudasobwa

関連する問題