class Dry::Monads::L

The List monad.

Constants

EMPTY

Empty list

Maybe

List of maybes

Result

List of results

Task

List of tasks

Try

List of tries

Validated

List of validation results

Attributes

to_a[R]

Internal array value

to_ary[R]

Internal array value

type[R]

Internal array value

value[R]

Internal array value

Private Class Methods

[](*values) click to toggle source

Builds a list.

@param values [Array<Object>] List elements @return [List]

# File lib/dry/monads/list.rb, line 12
def [](*values)
  new(values)
end
coerce(value, type = nil) click to toggle source

Coerces a value to a list. ‘nil` will be coerced to an empty list.

@param value [Object] Value @param type [Monad] Embedded monad type (used in case of list of monadic values) @return [List]

# File lib/dry/monads/list.rb, line 21
def coerce(value, type = nil)
  if value.nil?
    List.new([], type)
  elsif value.respond_to?(:to_ary)
    values = value.to_ary

    if !values.empty? && type.nil? && values[0].respond_to?(:monad)
      List.new(values, values[0].monad)
    else
      List.new(values, type)
    end
  else
    raise TypeError, "Can't coerce #{value.inspect} to List"
  end
end
new(value, type = nil) click to toggle source

@api private

# File lib/dry/monads/list.rb, line 85
def initialize(value, type = nil)
  @value = value
  @type = type
end
pure(value = Undefined, type = nil, &block) click to toggle source

Wraps a value with a list.

@param value [Object] any object @return [List]

# File lib/dry/monads/list.rb, line 41
def pure(value = Undefined, type = nil, &block)
  if value.equal?(Undefined)
    new([block])
  elsif block
    new([block], value)
  else
    new([value], type)
  end
end
unfold(state, type = nil) { |state| ... } click to toggle source

Iteratively builds a new list from a block returning Maybe values

@see hackage.haskell.org/package/base-4.12.0.0/docs/Data-List.html#g:9

@param state [Object.new] Initial state @param type [#pure] Type of list element @return [List]

# File lib/dry/monads/list.rb, line 58
def unfold(state, type = nil)
  xs = []

  loop do
    m = yield(state)

    if m.some?
      state, x = m.value!
      xs << x
    else
      break
    end
  end

  new(xs, type)
end

Private Instance Methods

+(other) click to toggle source

Concatenates two lists.

@example

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

@param other [List] Other list @return [List]

# File lib/dry/monads/list.rb, line 147
def +(other)
  List.new(to_ary + other.to_ary)
end
apply(list = Undefined, &block) click to toggle source

Applies the stored functions to the elements of the given list.

@param list [List] @return [List]

# File lib/dry/monads/list.rb, line 308
def apply(list = Undefined, &block)
  v = Undefined.default(list, &block)
  fmap(Curry).bind { |f| v.fmap { f.(_1) } }
end
bind(*args) { |_1, *args| ... } click to toggle source

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.

@example

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

@param args [Array<Object>] arguments will be passed to the block or proc @return [List]

# File lib/dry/monads/list.rb, line 101
def bind(*args)
  if block_given?
    List.coerce(value.map { yield(_1, *args) }.reduce([], &:+))
  else
    obj, *rest = args
    List.coerce(value.map { obj.(_1, *rest) }.reduce([], &:+))
  end
end
coerce(other) click to toggle source
# File lib/dry/monads/list.rb, line 376
def coerce(other)
  self.class.coerce(other)
end
collect() { |x| ... } click to toggle source

Iterates over the list and collects Some values.

@example with block syntax

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

@example without block

List[Some(5), None(), Some(3)].collect.map { |x| x * 2 }
# => [10, 6]

@return [List]

# File lib/dry/monads/list.rb, line 345
def collect
  if block_given?
    collected = value.each_with_object([]) do |x, ys|
      y = yield(x)
      ys << y.value! if y.some?
    end

    List.new(collected)
  else
    Enumerator.new do |g|
      value.each { g << _1.value! if _1.some? }
    end
  end
end
deconstruct() click to toggle source

Pattern matching

@example

case List[1, 2, 3]
in List[1, 2, x] then ...
in List[Integer, _, _] then ...
in List[0..2, _, _] then ...
end

@api private

# File lib/dry/monads/list.rb, line 370
def deconstruct
  value
end
empty?() click to toggle source

Whether the list is empty.

@return [TrueClass, FalseClass]

# File lib/dry/monads/list.rb, line 203
def empty?
  value.empty?
end
filter(&block) click to toggle source

Filters elements with a block

@return [List]

# File lib/dry/monads/list.rb, line 217
def filter(&block)
  coerce(value.select(&block))
end
Also aliased as: select
first() click to toggle source

Returns the first element.

@return [Object]

# File lib/dry/monads/list.rb, line 170
def first
  value.first
end
fmap(*args) { |_1, *args| ... } click to toggle source

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.

@example

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

@param args [Array<Object>] arguments will be passed to the block or proc @return [List]

# File lib/dry/monads/list.rb, line 119
def fmap(*args)
  if block_given?
    List.new(value.map { yield(_1, *args) })
  else
    obj, *rest = args
    List.new(value.map { obj.(_1, *rest) })
  end
end
fold_left(initial, &block) click to toggle source

Folds the list from the left.

@param initial [Object] Initial value @return [Object]

# File lib/dry/monads/list.rb, line 185
def fold_left(initial, &block)
  value.reduce(initial, &block)
end
Also aliased as: foldl, reduce
fold_right(initial) { |b, a| ... } click to toggle source

Folds the list from the right.

@param initial [Object] Initial value @return [Object]

# File lib/dry/monads/list.rb, line 195
def fold_right(initial)
  value.reverse.reduce(initial) { |a, b| yield(b, a) }
end
Also aliased as: foldr
foldl(initial, &block)
Alias for: fold_left
foldr(initial)
Alias for: fold_right
head() click to toggle source

Returns the first element wrapped with a ‘Maybe`.

@return [Maybe<Object>]

# File lib/dry/monads/list.rb, line 239
def head
  Monads::Maybe.coerce(value.first)
end
inspect() click to toggle source

Returns a string representation of the list.

@example

Dry::Monads::List[1, 2, 3].inspect # => "List[1, 2, 3]"

@return [String]

# File lib/dry/monads/list.rb, line 157
def inspect
  type_ann = typed? ? "<#{type.name.split("::").last}>" : ""
  "List#{type_ann}#{value.inspect}"
end
Also aliased as: to_s
last() click to toggle source

Returns the last element.

@return [Object]

# File lib/dry/monads/list.rb, line 177
def last
  value.last
end
map(&block) click to toggle source

Maps a block over the list. Acts as ‘Array#map`. If called without a block, this method returns an enumerator, not a List

@return [List,Enumerator]

# File lib/dry/monads/list.rb, line 132
def map(&block)
  if block_given?
    fmap(block)
  else
    value.map
  end
end
monad() click to toggle source

Returns the List monad.

@return [Monad]

# File lib/dry/monads/list.rb, line 316
def monad
  List
end
reduce(initial, &block)
Alias for: fold_left
reverse() click to toggle source

Reverses the list.

@return [List]

# File lib/dry/monads/list.rb, line 232
def reverse
  coerce(value.reverse)
end
select(&block)
Alias for: filter
size() click to toggle source

List size.

@return [Integer]

# File lib/dry/monads/list.rb, line 225
def size
  value.size
end
sort() click to toggle source

Sorts the list.

@return [List]

# File lib/dry/monads/list.rb, line 210
def sort
  coerce(value.sort)
end
tail() click to toggle source

Returns list’s tail.

@return [List]

# File lib/dry/monads/list.rb, line 246
def tail
  coerce(value.drop(1))
end
to_monad() click to toggle source

Returns self.

@return [List]

# File lib/dry/monads/list.rb, line 323
def to_monad
  self
end
to_s()
Alias for: inspect
traverse(proc = nil, &block) click to toggle source

Traverses the list with a block (or without it). This methods “flips” List structure with the given monad (obtained from the type). Note that traversing requires the list to be typed. Also if a block given, its returning type must be equal list’s type.

@example

List<Result>[Success(1), Success(2)].traverse # => Success([1, 2])
List<Maybe>[Some(1), None, Some(3)].traverse # => None

@return [Monad] Result is a monadic value

# File lib/dry/monads/list.rb, line 289
def traverse(proc = nil, &block)
  unless typed?
    raise StandardError, "Cannot traverse an untyped list"
  end

  cons = type.pure { |list, i| list + List.pure(i) }
  with = proc || block || Traverse[type]

  foldl(type.pure(EMPTY)) do |acc, el|
    cons
      .apply(acc)
      .apply { with.(el) }
  end
end
typed(type = nil) click to toggle source

Turns the list into a typed one. Type is required for some operations like .traverse.

@param type [Monad] Monad instance @return [List] Typed list

# File lib/dry/monads/list.rb, line 255
def typed(type = nil)
  if type.nil?
    if size.zero?
      raise ArgumentError, "Cannot infer a monad for an empty list"
    else
      self.class.warn(
        "Automatic monad inference is deprecated, pass a type explicitly "\
        "or use a predefined constant, e.g. List::Result\n"\
        "#{caller.find { _1 !~ %r{(lib/dry/monads)|(gems)} }}"
      )
      self.class.new(value, value[0].monad)
    end
  else
    self.class.new(value, type)
  end
end
typed?() click to toggle source

Whether the list is types

@return [Boolean]

# File lib/dry/monads/list.rb, line 275
def typed?
  !type.nil?
end