如何在 Elixir 中编写 Monadic 值?

How To Code A Monadic Value In Elixir?

所以我试图更好地理解 monad 的概念。我试图从简单开始;那就是构建一个非常简单的 Elixir 模块,只有一个 return 函数。这个:

defmodule MonadTest do
   def return(s), do: fn s -> s end
end

然后我把这个函数绑定到一个变量上:

f = &MonadTest.return/1

然后我尝试这样调用函数:

f.(12)

但是我没有返回 12,而是得到了函数。像这样:

iex(22)> r = f.(12)
#Function<0.122071921/1 in MonadTest.return/1>
iex(23)> r
#Function<0.122071921/1 in MonadTest.return/1>

我确定我遗漏了一些明显的东西——但我在这里遗漏了什么?

monad 是一种描述操作如何链接在一起的方式

monad 最常见的形式是将一个函数的输出传递到链中的下一个函数。 Elixir 为此提供了管道运算符 |>。然而:

基于 OP,不想改变元数:

传递给命名函数的原始参数从未被使用。如果你想保持命名函数的元数,但希望匿名函数返回值"chained",你可以这样实现非匿名函数:

  defmodule MonadTest do
    def return(s), do: fn -> s end
  end
  f = MonadTest.return(1)
  f.()

或者,您可以像在 post:

中那样匿名使用该函数
  defmodule MonadTest do
    def return(s), do: fn -> s end
  end
  f = &MonadTest.return/1
  f.(1).()

我认为这里有两件事我们可以澄清。 (1) 是 &<NamedFunction>/<arity> 语法,第二个是如何传递参数。

语法 &MonadTest.return/1 将生成一个与命名函数 MonadTest.return 具有相同定义的匿名函数。

这通常在将命名函数作为参数传递时使用,例如如果您需要在可枚举方法中使用 MonadTest。return/1,例如 Enum.map(1..5, &MonadTest .return/1).

在我的示例中,我不会将参数传递给命名函数,因为您将它传递给新定义的 MonadTest 中的匿名函数。return/0。

出于您的目的,您可能不需要生成匿名函数,而是可以直接引用命名函数:

  defmodule MonadTest do
    def return, do: fn s -> s end
  end
  f = MonadTest.return
  f.(12)

如果您确实需要 MonadTest 是匿名的,则需要调用它,然后将参数传递给嵌套在其中的匿名函数。

  defmodule MonadTest do
    def return, do: fn s -> s end
  end
  f = &MonadTest.return/0
  f.().(12)