class_docstr: This class is a singleton builder to construct a MIL program. For more
  information, see `Create a MIL program <https://coremltools.readme.io/docs/model-intermediate-language#create-a-mil-program>`_.
  
  Importing ``.ops`` triggers the installation of all MIL ops into the Builder.
  For details on each op, see `MIL ops <https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html>`_.
  
  Examples
  --------
  
  >>> from coremltools.converters.mil.mil import Builder as mb
  >>> from coremltools.converters.mil.mil import Program, Function
  
  >>> prog = Program()
  >>> func_inputs = {"x": mb.placeholder(shape=[2,3]),
  >>>                "y": mb.placeholder(shape=[2,3])}
  >>> with Function(func_inputs) as ssa_fun:
  >>>   x, y = ssa_fun.inputs['x'], ssa_fun.inputs['y']
  >>>   res_var = mb.add(x=x, y=y) # created within ssa_fun block
  >>>   ssa_fun.set_outputs([res_var])
  >>> prog.add_function("main", ssa_fun)
  
  >>> # Importing ops triggers installation of all ops into Builder.
  >>> from .ops import defs as _ops
docstr: Utility to construct a pymil function.
docstr_tok: ["Utility","to","construct","a","pymil","function","."]
code: def _create_function(
      main_block: Callable,
      input_specs: Optional[List[Placeholder]] = None,
      opset_version: Optional[AvailableTarget] = None,
  ):
      """
      Utility to construct a pymil function.
      """
      if input_specs is None:
          input_specs = []
  
      # validate number of function inputs
      num_args = main_block.__code__.co_argcount
      arg_names = list(main_block.__code__.co_varnames)[:num_args]
      if len(input_specs) != num_args:
          raise ValueError(
              f"{main_block.__name__} expects {num_args} inputs: {arg_names}. Got {len(input_specs)} input_specs."
          )
  
      # create the function
      input_spec_dict = {k: v for k, v in zip(arg_names, input_specs)}
      with Function(input_spec_dict, opset_version) as func:
          input_vars = [func.inputs[a] for a in arg_names]
          outputs = main_block(*input_vars)
          if isinstance(outputs, tuple):
              outputs = list(outputs)
          elif not isinstance(outputs, list):
              outputs = [outputs]
          func.set_outputs(outputs)
  
      # infer the opset version if not provided
      max_opset_version, _ = func.get_max_opset_version_and_op()
      if opset_version is None:
          func.opset_version = max_opset_version
  
      return func
  
imports: import numbers
  from collections import defaultdict
  from typing import Callable, List, Optional
  import numpy
  from coremltools import _logger
  from coremltools.converters.mil._deployment_compatibility import AvailableTarget
  from coremltools.converters.mil.mil.types.symbolic import any_symbolic
  from .block import Function, curr_block
  from .input_type import InternalInputType, ListOrTensorInputType, TensorInputType, TupleInputType
  from .program import Placeholder, Program
  from .var import InternalVar, Var
label_desc: Use image node_id 8 for calling the Builder obj's underlying member method code with example usage: obj._create_function(main_block, input_specs, opset_version) and returns: func