def _compile_function_expression(self,
                                     expr: Expression,
                                     scope: Dict[str, TensorFluent],
                                     batch_size: Optional[int] = None,
                                     noise: Optional[List[tf.Tensor]] = None) -> TensorFluent:
        '''Compile a function expression `expr` into a TensorFluent
        in the given `scope` with optional batch size.

        Args:
            expr (:obj:`rddl2tf.expr.Expression`): A RDDL function expression.
            scope (Dict[str, :obj:`rddl2tf.fluent.TensorFluent`]): A fluent scope.
            batch_size (Optional[size]): The batch size.

        Returns:
            :obj:`rddl2tf.fluent.TensorFluent`: The compiled expression as a TensorFluent.
        '''
        etype = expr.etype
        args = expr.args

        if len(args) == 1:

            etype2func = {
                'abs':    TensorFluent.abs,
                'exp':    TensorFluent.exp,
                'log':    TensorFluent.log,
                'sqrt':   TensorFluent.sqrt,
                'cos':    TensorFluent.cos,
                'sin':    TensorFluent.sin,
                'tan':    TensorFluent.tan,
                'acos':   TensorFluent.acos,
                'arccos': TensorFluent.acos,
                'asin':   TensorFluent.asin,
                'arcsin': TensorFluent.asin,
                'atan':   TensorFluent.atan,
                'arctan': TensorFluent.atan,
                'round':  TensorFluent.round,
                'ceil':   TensorFluent.ceil,
                'floor':  TensorFluent.floor
            }

            if etype[1] not in etype2func:
                raise ValueError('Invalid unary function expression:\n{}'.format(expr))

            op = etype2func[etype[1]]
            x = self._compile_expression(args[0], scope, batch_size, noise)
            fluent = op(x)

        else:
            etype2func = {
                'pow': TensorFluent.pow,
                'max': TensorFluent.max,
                'min': TensorFluent.min
            }

            if etype[1] not in etype2func:
                raise ValueError('Invalid binary function expression:\n{}'.format(expr))

            op = etype2func[etype[1]]
            x = self._compile_expression(args[0], scope, batch_size, noise)
            y = self._compile_expression(args[1], scope, batch_size, noise)
            fluent = op(x, y)

        return fluent
Compile a function expression `expr` into a TensorFluent
        in the given `scope` with optional batch size.

        Args:
            expr (:obj:`rddl2tf.expr.Expression`): A RDDL function expression.
            scope (Dict[str, :obj:`rddl2tf.fluent.TensorFluent`]): A fluent scope.
            batch_size (Optional[size]): The batch size.

        Returns:
            :obj:`rddl2tf.fluent.TensorFluent`: The compiled expression as a TensorFluent.