thunk v0.3.1 Thunk View Source

Laziness in Elixir. Thunks are computations that have not yet happened. This module provides the thunk type and functions for manipulating and creating thunks.

Thunks allow for setting up a computation and transforming it without evaluating it. A thunk can be used by other thunks and evaluation is shared.

Example

defmodule Infinity do
  require Thunk  

  @doc """
  An infinite list that just repeats its argument.

  ## Example

      iex> xs = Infinity.repeatedly(1)
      #Thunk<...>
      iex> [h | t] = Thunk.force(xs)
      [1 | #Thunk<...>]
  """
  def repeatedly(x) do
    Thunk.suspend([x | repeatedly(x)])
  end
end

Link to this section Summary

Types

Alias for any

t()

Thunk type

Functions

Given a thunk with a function and a thunk with it’s argument, returns a thunk with the result of their application

Copies a thunk. When a thunk is forced it ceases to exist, so this function is useful for holding onto a result should it be forced

Deletes a thunk, to be used if the thunk does not need to ever be evaluated

Is thunk still around?

Forces a thunk. Raises a ThunkError if already forced or deleted

Applies a function to a thunk

Suspends a value in a thunk. Doesn’t evaluate it’s argument. Can be used as a do block as well

Is value a thunk?

Link to this section Types

Link to this type element() View Source
element() :: any()

Alias for any.

Thunk type.

Link to this section Functions

Link to this function apply(thunk_f, thunk_x) View Source
apply(t(), t()) :: t()

Given a thunk with a function and a thunk with it’s argument, returns a thunk with the result of their application.

Example

iex> defmodule ThunkyMath do
...>   require Thunk   
...>
...>   # Add two thunks
...>   def add(x, y) do
...>    addr = fn n1 -> fn n2 -> n1 + n2 end end
...>     Thunk.map(x, addr)
...>     |> Thunk.apply(y)
...>   end
...> end
iex> x = Thunk.suspend(12)
iex> y = Thunk.suspend(13)
iex> z = ThunkyMath.add(x, y)
#Thunk<...>
iex> Thunk.force(z)
25
Link to this function copy(thunk) View Source
copy(t()) :: t()

Copies a thunk. When a thunk is forced it ceases to exist, so this function is useful for holding onto a result should it be forced.

Example

iex> thunk = Thunk.suspend(:some_computation)
iex> thunk_copy = Thunk.copy(thunk)
iex> Thunk.force(thunk)
iex> Thunk.exists?(thunk)
false
iex> Thunk.force(thunk_copy)
:some_computation
Link to this function delete(thunk) View Source
delete(t()) :: true

Deletes a thunk, to be used if the thunk does not need to ever be evaluated.

Example

iex> thunk = Thunk.suspend(:some_computation)
iex> Thunk.delete(thunk)
iex> Thunk.exists?(thunk)
false
Link to this function exists?(thunk) View Source
exists?(t()) :: boolean()

Is thunk still around?

Link to this function force(thunk) View Source
force(t()) :: any()

Forces a thunk. Raises a ThunkError if already forced or deleted.

Example

iex> thunk = Thunk.suspend(:value)
iex> Thunk.force(thunk)
:value
Link to this function map(thunk, f) View Source
map(t(), (element() -> any())) :: t()

Applies a function to a thunk.

Example

iex> thunk_x = Thunk.suspend(1)
iex> thunk_y = Thunk.map(thunk_x, fn x -> x + 1 end)
iex> Thunk.force(thunk_y)
2
Link to this macro suspend(x) View Source (macro)
suspend(any()) :: t()

Suspends a value in a thunk. Doesn’t evaluate it’s argument. Can be used as a do block as well.

Example

iex> Thunk.suspend(raise("Oops you evaluated me!"))
#Thunk<...>
iex> Thunk.suspend do
...>   x = 5
...>   y = 6
...>   x + y
...> end
#Thunk<...>

Is value a thunk?