简体   繁体   中英

How To Code A Monadic Value In Elixir?

So I'm trying to understand the idea of monads better. And I'm trying to start simple; that is building a very simple Elixir module with just a return function. This:

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

Then I bind the function to a variable in this way:

f = &MonadTest.return/1

Then I try to call the function like this:

f.(12)

But instead of getting back 12, I get the function. Like this:

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

I'm sure I'm missing something obvious--but what am I missing here?

A monad is a way of describing how operations are chained together .

The most common form of a monad is to pass output from one function into the next function in the chain. Elixir provides the pipe operator |> for that. However:

Based on OP, and not wanting to change the arity:

The original parameter being passed to the named function is never being used. If you want to maintain the arity of the named function, but want the value to be returned by the anonymous function "chained", you would implement the non-anonymous function as such:

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

alternatively, you can use the function anonymously as you did in your post:

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

I think there are 2 things going on here we can clarify. (1) is the &<NamedFunction>/<arity> syntax, and the second is how parameters are being passed.

The syntax &MonadTest.return/1 is going to generate an anonymous function with the same definition of the named function MonadTest.return .

This is generally used when passing a named function as a parameter, like if you needed to use MonadTest.return/1 in an enumerable method, such as Enum.map(1..5, &MonadTest.return/1).

In my example, I'm not going to pass a parameter to the named function, since you pass it to the anonymous function inside of newly defined MonadTest.return/0.

For your purposes, you probably don't need to generate the anonymous function, and instead can refer to the named function directly:

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

If you do need MonadTest to be anonymous, you will need to invoke it and then pass the parameter to the anonymous function nested within.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM