2017-10-10 1 views
2

je code suivant:Le passage d'une fonction à defimpl « pour » l'option

defprotocol Reversible do 
    @doc "Reverses data structure" 
    def reverse(term) 
end 

defimpl Reversible, for: [List, Map] do 
    def reverse(term), do: Enum.reverse(term) 
end 

Il fonctionne très bien, mais je veux énumérer tous les types dénombrables d'une certaine façon et de les utiliser dans d'autres endroits aussi.

donc j'ai essayé de le faire:

# constants.ex 
defmodule Constants do 
    @enumerables [List, Map] 
    def enumerables, do: @enumerables 
end 

# reversible.ex 
import Constants, only: [enumerables: 0] 

defprotocol Reversible do 
    def reverse(term) 
end 

defimpl Reversible, for: enumerables() do 
    def reverse(term), do: Enum.reverse(term) 
end 

Et j'ai une erreur:

== Compilation error in file lib/reversible.ex == 
** (FunctionClauseError) no function clause matching in Module.concat/2 

    The following arguments were given to Module.concat/2: 

     # 1 
     Reversible 

     # 2 
     [List, Map] 

    (elixir) lib/module.ex:562: Module.concat/2 
    lib/reversible.ex:8: (file) 
    (elixir) lib/kernel/parallel_compiler.ex:121: 
     anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1 

Comment résoudre ce problème?

Répondre

3

defimpl vérifie la valeur de for argument at compile time (macro argument) and if it's a list, it recurses over all items of the list. Puisque votre variable n'est pas une liste littérale, defimpl ne la traite pas comme une liste.

Vous pouvez contourner ce problème en itérer sur la liste et en invoquant defimpl sur vous-même chaque:

# constants.ex 
defmodule Constants do 
    @enumerables [List, Map] 
    def enumerables, do: @enumerables 
end 

# reversible.ex 
defprotocol Reversible do 
    def reverse(term) 
end 

for enumerable <- Constants.enumerables do 
    defimpl Reversible, for: enumerable do 
    def reverse(term), do: Enum.reverse(term) 
    end 
end 

Test:

$ iex -S mix 
iex(1)> Reversible.reverse [1, 2, 3] 
[3, 2, 1] 
iex(2)> Reversible.reverse %{1 => 2, 3 => 4} 
[{3, 4}, {1, 2}] 
+0

Je pensais que cette solution implique réimplémenter 'defimpl' dans d'une certaine façon et de déconner avec citation/unquote. Votre solution est simple et propre, merci! –