erlang - Elixir 中透析器的多态类型
问题描述
背景
我有一个struct
调用MyApp.Result
,它基本上是 Result Monad 的表示。该结构旨在成为操作成功和错误的正式结构表示:
defmodule MyApp.Result do
@enforce_keys [:type]
defstruct type: nil,
result: nil,
error_reason: nil,
error_details: nil,
input_parameters: []
@type type :: :ok | :error
@type result :: any()
@type reason :: atom() | nil
@type details :: any()
@type params :: [any()]
@type t() :: %__MODULE__{
type: type(),
result: result(),
error_reason: reason(),
error_details: details(),
input_parameters: params()
}
@spec ok :: __MODULE__.t()
def ok, do: %__MODULE__{type: :ok}
@spec ok(result()) :: __MODULE__.t()
def ok(result), do: %__MODULE__{type: :ok, result: result}
@spec error(reason()) :: __MODULE__.t()
def error(reason), do: %__MODULE__{type: :error, error_reason: reason}
@spec error(reason(), details()) :: __MODULE__.t()
def error(reason, details) do
%__MODULE__{type: :error, error_reason: reason, error_details: details}
end
@spec error(reason(), details(), params()) :: __MODULE__.t()
def error(reason, details, input) do
%__MODULE__{
type: :error,
error_reason: reason,
error_details: details,
input_parameters: input
}
end
问题
在向我的一位同事展示这一点时,他提出了一个很好的观点:
我看到你在这里尝试做什么,但是当我看到一个
MyApp.Result
结构时,我必须检查代码以了解result
字段内部的内容,以防成功。对我来说,这只是隐藏事物的另一层,如果操作成功,它并不清楚操作返回什么。
公平地说,我认为这是一个很好的观点。结果单子会隐藏计算结果,直到您需要它们。但我确实认为有一种更好的方法,一种我们仍然可以拥有一个 Result Monad 的方法,它明确显示结果字段的类型。
带透析器的多态类型
我相信我的问题的解决方案可能是透析器的多态类型。引用一篇文章:
来自Learn You Some Erlang 当我说我们可以将整数列表定义为
[integer()]
orlist(integer())
时,那些是多态类型。它是一种接受类型作为参数的类型。为了使我们的队列只接受整数或卡片,我们可以将其类型定义为:
-type queue(Type) :: {fifo, list(Type), list(Type)}. -export_type([queue/1]).
所以现在我知道这在 erlang 中是可能的。如果那里有可能,那么在 Elixir 中也应该有可能。
错误
因此,我将代码更改为以下内容:
@enforce_keys [:type]
defstruct type: nil,
result: nil,
error_reason: nil,
error_details: nil,
input_parameters: []
@type type :: :ok | :error
@type result :: Type
@type reason :: atom() | nil
@type details :: any()
@type params :: [any()]
@type t(Type) :: %__MODULE__{
type: type(),
result: result(),
error_reason: reason(),
error_details: details(),
input_parameters: params()
}
@spec ok :: BusyBee.Wrappers.FFmpeg.Result.t(nil)
@spec ok :: __MODULE__.t()
def ok, do: %__MODULE__{type: :ok}
@spec ok(result()) :: __MODULE__.t(Type)
def ok(result), do: %__MODULE__{type: :ok, result: result}
然而,这打破了。我不知道如何使用透析器在 Elixir 中表示多态类型。
问题
如何修复此代码,以便我的透析器知道 Result 是多态类型?
解决方案
推荐阅读
- powerbi - 将 MDX 查询加载到 PowerBI 时,将其加载到 SSMS 时出现问题,没有问题
- python - 出现错误“UnboundLocalError:分配前引用的局部变量'start_time'”
- javascript - 如何保持所有 activeDots 始终“活跃”而不是悬停在数据点上(重新图表)
- javascript - 将对象数组转换为一个逗号分隔的对象
- java - 如何在 Java 中修复 NoSuchMethodError
- google-cloud-platform - 错误:构建步骤 0“gcr.io/cloud-builders/docker”失败:退出状态 1
- java - Android Studio 3.4 - 无法调试 onClickListeners
- c# - WinForms ReportViewer HTML 交互不工作
- dart - 每个平台依赖项
- c# - 下拉列表未按预期显示