class Dry::Monads::L
The List
monad.
Constants
Attributes
Internal array value
Internal array value
Internal array value
Internal array value
Private Class Methods
Builds a list.
@param values [Array<Object>] List
elements @return [List]
# File lib/dry/monads/list.rb, line 12 def [](*values) new(values) end
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
@api private
# File lib/dry/monads/list.rb, line 85 def initialize(value, type = nil) @value = value @type = type end
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
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
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
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
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
# File lib/dry/monads/list.rb, line 376 def coerce(other) self.class.coerce(other) end
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
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
Whether the list is empty.
@return [TrueClass, FalseClass]
# File lib/dry/monads/list.rb, line 203 def empty? value.empty? end
Filters elements with a block
@return [List]
# File lib/dry/monads/list.rb, line 217 def filter(&block) coerce(value.select(&block)) end
Returns the first element.
@return [Object]
# File lib/dry/monads/list.rb, line 170 def first value.first end
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
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
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
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
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
Returns the last element.
@return [Object]
# File lib/dry/monads/list.rb, line 177 def last value.last end
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
Reverses the list.
@return [List]
# File lib/dry/monads/list.rb, line 232 def reverse coerce(value.reverse) end
Sorts the list.
@return [List]
# File lib/dry/monads/list.rb, line 210 def sort coerce(value.sort) end
Returns list’s tail.
@return [List]
# File lib/dry/monads/list.rb, line 246 def tail coerce(value.drop(1)) end
Returns self.
@return [List]
# File lib/dry/monads/list.rb, line 323 def to_monad self end
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
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
Whether the list is types
@return [Boolean]
# File lib/dry/monads/list.rb, line 275 def typed? !type.nil? end