如何在Elixir中编码Monadic值?

时间:2015-07-21 16:30:11

标签: monads elixir

所以我试图更好地理解monad的想法。我试着开始简单;这是一个非常简单的Elixir模块,只有一个返回功能。这样:

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>

我确定我错过了一些明显的东西 - 但我在这里错过了什么?

1 个答案:

答案 0 :(得分:7)

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

monad最常见的形式是将输出从一个函数传递到链中的下一个函数。 Elixir为此提供管道操作员|>。但是:

基于OP,不想改变arity:

永远不会使用传递给指定函数的原始参数。如果你想维护命名函数的arity,但希望匿名函数“chained”返回值,你可以实现非匿名函数:

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

或者,您可以像在帖子中那样匿名使用该功能:

  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,&amp; 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)