Полиморфизм в Elixir
Полиморфизм — это возможность использования единого интерфейса сущностями различных типов. По сути, это свойство позволяет различным типам данных взаимодействовать с одной и той же функцией, в результате чего этим типам становится свойственно одинаковое поведение. Для «чистой» реализации полиморфизма в Elixir существует механизм протоколов.
Создадим простенький протокол для перевода значений температуры по шкале Кельвина или Фаренгейта в градусы Цельсия.
defmodule Kelvin do
defstruct name: "Kelvin", symbol: "K", degree: 0
end
defmodule Fahrenheit do
defstruct name: "Fahrenheit", symbol: "°F", degree: 0
end
defmodule Celsius do
defstruct name: "Celsius", symbol: "°C", degree: 0
end
defprotocol Temperature do
@doc """
Convert Kelvin and Fahrenheit to Celsius degree
"""
def to_celsius(degree)
end
defimpl Temperature, for: Kelvin do
@doc """
Deduct 273.15
"""
def to_celsius(kelvin) do
celsius_degree = kelvin.degree - 273.15
%Celsius{degree: celsius_degree}
end
end
defimpl Temperature, for: Fahrenheit do
@doc """
Deduct 32, then multiply by 5, then divide by 9
"""
def to_celsius(fahrenheit) do
celsius_degree = (fahrenheit.degree - 32) * 5 / 9
%Celsius{degree: celsius_degree}
end
end
Итак, конвертеры для шкал Кельвина и Фаренгейта готовы. Опробуем их на практике:
iex> fahrenheit = %Fahrenheit{degree: 45}
%Fahrenheit{degree: 45, name: "Fahrenheit", symbol: "°F"}
iex> celsius = Temperature.to_celsius(fahrenheit)
%Celsius{degree: 7.22, name: "Celsius", symbol: "°C"}
iex> kelvin = %Kelvin{degree: 300}
%Kelvin{degree: 300, name: "Kelvin", symbol: "K"}
iex> celsius = Temperature.to_celsius(kelvin)
%Celsius{degree: 26.85, name: "Celsius", symbol: "°C"}
А теперь попытаемся конвертировать какой-нибудь тип данных, не содержащий реализацию функции to_celsius
:
iex> Temperature.to_celsius(%{degree: 12})
** (Protocol.UndefinedError) protocol Temperature not implemented for %{degree: 12}
iex:11: Temperature.impl_for!/1
iex:15: Temperature.to_celsius/1
Если необходимо охватить все типы данных, то создайте для них отдельную реализацию для типа Any
. И наконец, рекомендую обратить внимание на исходный код Enum
и String.Char
, которые являются прекрасными примерами полиморфизма в Elixir.
Успехов в функциональном программировании! ♥