<commit_before># frozen_string_literal: true

require "dry/core/equalizer"

require "dry/monads/maybe"
require "dry/monads/task"
require "dry/monads/result"
require "dry/monads/try"
require "dry/monads/validated"
require "dry/monads/transformer"
require "dry/monads/curry"

module Dry
  module Monads
    # The List monad.
    class List
      class << self
        # Builds a list.
        #
        # @param values [Array<Object>] List elements
        # @return [List]
        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]
        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

        # Wraps a value with a list.
        #
        # @param value [Object] any object
        # @return [List]
        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 https://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]
        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
      end

      extend Dry::Core::Deprecations[:"dry-monads"]

      include Dry::Equalizer(:value, :type)
      include Transformer

      # Internal array value
      attr_reader :value, :type

      # @api private
      def initialize(value, type = nil)
        @value = value
        @type = type
      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]
      def bind(*args)
        if block_given?
          List.coerce(value.map { |v| yield(v, *args) }.reduce([], &:+))
        else
          obj, *rest = args
          List.coerce(value.map { |v| obj.(v, *rest) }.reduce([], &:+))
        end
      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]
      def fmap(*args)
        if block_given?
          List.new(value.map { |v| yield(v, *args) })
        else
          obj, *rest = args
          List.new(value.map { |v| obj.(v, *rest) })
        end
      end

      # Maps a block over the list. Acts as `Array#map`.
      # Note that this method returns an Array instance, not a List
      #
      # @return [List,Enumerator]
      def map(&block)
        if block
          fmap(block)
        else
          value.map(&block)<commit_msg>Update docs on List#map (fixes #121)<commit_after># frozen_string_literal: true

require "dry/core/equalizer"

require "dry/monads/maybe"
require "dry/monads/task"
require "dry/monads/result"
require "dry/monads/try"
require "dry/monads/validated"
require "dry/monads/transformer"
require "dry/monads/curry"

module Dry
  module Monads
    # The List monad.
    class List
      class << self
        # Builds a list.
        #
        # @param values [Array<Object>] List elements
        # @return [List]
        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]
        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

        # Wraps a value with a list.
        #
        # @param value [Object] any object
        # @return [List]
        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 https://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]
        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
      end

      extend Dry::Core::Deprecations[:"dry-monads"]

      include Dry::Equalizer(:value, :type)
      include Transformer

      # Internal array value
      attr_reader :value, :type

      # @api private
      def initialize(value, type = nil)
        @value = value
        @type = type
      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]
      def bind(*args)
        if block_given?
          List.coerce(value.map { |v| yield(v, *args) }.reduce([], &:+))
        else
          obj, *rest = args
          List.coerce(value.map { |v| obj.(v, *rest) }.reduce([], &:+))
        end
      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]
      def fmap(*args)
        if block_given?
          List.new(value.map { |v| yield(v, *args) })
        else
          obj, *rest = args
          List.new(value.map { |v| obj.(v, *rest) })
        end
      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]
      def map(&block)
        if block_given?
          fmap(block)
        else
          value.map
{'fraction_non_alphanumeric': 0.1138549210495073, 'fraction_numerical': 0.006292294906802802, 'mean_word_length': 1.6641366223908918, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1269207', 'n_tokens_mistral': 2670, 'n_tokens_neox': 2559, 'n_words': 818}