docs: def memoize(func=None, maxlen=None):
      """Cache a function's return value each time it is called.
      
      This function serves as a function decorator to provide a caching of
      evaluated fitness values. If called later with the same arguments, 
      the cached value is returned instead of being re-evaluated.
      
      This decorator assumes that candidates are individually pickleable, 
      and their pickled values are used for hashing into a dictionary. It 
      should be used when evaluating an *expensive* fitness 
      function to avoid costly re-evaluation of those fitnesses. The 
      typical usage is as follows::
      
          @memoize
          def expensive_fitness_function(candidates, args):
              # Implementation of expensive fitness calculation
              pass
              
      It is also possible to provide the named argument *maxlen*, which
      specifies the size of the memoization cache to use. (If *maxlen* is
      ``None``, then an unbounded cache is used.) Once the size of the cache 
      has reached *maxlen*, the oldest element is replaced by the newest
      element in order to keep the size constant. This usage is as follows::
      
          @memoize(maxlen=100)
          def expensive_fitness_function(candidates, args):
              # Implementation of expensive fitness calculation
              pass
              
      .. warning:: The ``maxlen`` parameter must be passed as a named keyword
         argument, or an ``AttributeError`` will be raised (e.g., saying 
         ``@memoize(100)`` will cause an error).
      
      """
      if func is not None:
          cache = BoundedOrderedDict(maxlen=maxlen)
          @functools.wraps(func)
          def memo_target(candidates, args):
              fitness = []
              for candidate in candidates:
                  lookup_value = pickle.dumps(candidate, 1)
                  if lookup_value not in cache:
                      cache[lookup_value] = func([candidate], args)[0]
                  fitness.append(cache[lookup_value])
              return fitness
          return memo_target
      else:
          def memoize_factory(func):
              return memoize(func, maxlen=maxlen)
          return memoize_factory