List

bind

Lifts a block/proc and runs it against each member of the list. The block must return a value coercible to a list. As in other monads if no block given the first argument will be treated as callable and used instead.

require 'dry/monads/list'

M = Dry::Monads

M::List[1, 2].bind { |x| [x + 1] } # => List[2, 3]
M::List[1, 2].bind(-> x { [x, x + 1] }) # => List[1, 2, 2, 3]

M::List[1, nil].bind { |x| [x + 1] } # => error

collect

Works differently than Enumerable#collect: the block must return Maybe types, Some values are retained and None is discarded. As in other monads if no block given the first argument will be treated as callable and used instead.

require 'dry/monads/list'

M = Dry::Monads

n = 20
M::List[10, 5, 0].collect do |divisor|
  if divisor.zero?
    M::None()
  else
    M::Some(n / divisor)
  end
end
# => List[2, 4]

M::List[M::Some(1), M::None(), M::Some(2), M::None(), M::Some(3)].collect # => List[1, 2, 3]

leap_year = proc do |year|
  if year % 400 == 0
    M::Some(year)
  elsif year % 100 == 0
    M::None()
  elsif year % 4 == 0
    M::Some(year)
  else
    M::None()
  end
end

M::List[2020, 2021, 2022, 2023, 2024].collect(leap_year) # => List[2020, 2024]

fmap

Maps a block over the list. Acts as Array#map. As in other monads, if no block given the first argument will be treated as callable and used instead.

require 'dry/monads/list'

M = Dry::Monads

M::List[1, 2].fmap { |x| x + 1 } # => List[2, 3]

value

You always can unwrap the result by calling value.

require 'dry/monads/list'

M = Dry::Monads

M::List[1, 2].value # => [1, 2]

Concatenation

require 'dry/monads/list'

M = Dry::Monads

M::List[1, 2] + M::List[3, 4] # => List[1, 2, 3, 4]

head and tail

head returns the first element wrapped with a Maybe.

require 'dry/monads/list'

M = Dry::Monads

M::List[1, 2, 3, 4].head # => Some(1)
M::List[1, 2, 3, 4].tail # => List[2, 3, 4]

traverse

Traverses the list with a block (or without it). This method "flips" List structure with the given monad (obtained from the type).

Note that traversing requires the list to be typed.

require 'dry/monads/list'

M = Dry::Monads

M::List[M::Success(1), M::Success(2)].typed(M::Result).traverse # => Success(List[1, 2])
M::List[M::Maybe(1), M::Maybe(nil), M::Maybe(3)].typed(M::Maybe).traverse # => None

# also, you can use fmap with #traverse

M::List[1, 2].fmap { |x| M::Success(x) }.typed(M::Result).traverse # => Success(List[1, 2])
M::List[1, nil, 3].fmap { |x| M::Maybe(x) }.typed(M::Maybe).traverse # => None

octocatEdit on GitHub