diff --git a/libwccl/ops/operator.h b/libwccl/ops/operator.h
index 5997c5ab8c67d04806fbf712f83601fcd5252b15..19dc17e2ecb51e3d9b7c9d35855cccd42c39f39b 100644
--- a/libwccl/ops/operator.h
+++ b/libwccl/ops/operator.h
@@ -1,50 +1,345 @@
 #ifndef LIBWCCL_OPS_OPERATOR_H
 #define LIBWCCL_OPS_OPERATOR_H
 
-#include <libcorpus2/tagset.h>
-#include <unicode/unistr.h>
-#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <libwccl/ops/parsedexpression.h>
+#include <libwccl/ops/functions.h>
+#include <libwccl/ops/constant.h>
 
 namespace Wccl {
 
 /**
- * Abstract base class for WCCL operators
+ * Abstract base class for WCCL expressions that are functional
+ * operators
  */
-class Operator : public boost::noncopyable {
+class FunctionalOperator : public ParsedExpression
+{
 public:
 	/**
-	 * Name of the Operator, in general a tagset is required,
-	 * but some classes might not need that, so by default just forward
-	 * to raw_operator_name();
+	 * Applies the functional operator to given sentence context.
+	 * @returns Result of the application, in terms of base type of Value.
 	 */
-	virtual const std::string operator_name(const Corpus2::Tagset& /*tagset*/) const {
-		return raw_operator_name();
-	}
+	virtual boost::shared_ptr<const Value> base_apply(const SentenceContext& sc) = 0;
+
 	/**
-	 * Name of the Operator that does not require a tagset,
-	 * might be incomplete and/or contain internal info.
-	 *
-	 * Prefer operator_name(tagset).
+	 * @returns A copy of the expression, with values of the variables
+	 * copied as well.
+	 * @see clone_clean_ptr - convenience version that returns clean copy.
 	 */
-	virtual const std::string raw_operator_name() const = 0;
+	boost::shared_ptr<FunctionalOperator> clone_ptr() const;
+
 	/**
-	 * String representation of the operator, by default it's just
-	 * the name of the operator returned by operator_name(tagset)
+	 * @returns A copy of the expression, with values of the variables
+	 * set to their defaults.
+	 * @see clone_ptr - a version that keeps values of the variables.
 	 */
-	virtual std::string to_string(const Corpus2::Tagset& tagset) const {
-		return operator_name(tagset);
-	}
+	boost::shared_ptr<FunctionalOperator> clone_clean_ptr() const;
+
+protected:
+	explicit FunctionalOperator(const Variables& variables);
+
+	FunctionalOperator* clone_internal() const = 0;
+};
+
+
+/**
+ * Represents a parsed WCCL functional operator that returns a value of given type.
+ * @note The class methods are not thread-safe, but you can use clone method
+ * to acquire a separate copy of the Operator, and the copy can be used concurrently.
+ * @todo need to change copying of Variables once a clone method is available for them.
+ */
+template <class T>
+class Operator : public FunctionalOperator, public detail::PtrCleanCloneable<Operator<T> >
+{
+public:
+	Operator(const boost::shared_ptr<Function<T> >& body, const Variables& variables);
+
 	/**
-	 * String representation of the operator that does not require a tagset,
-	 * might be incomplete and/or contain internal info.
-	 *
-	 * By default it is just the raw_operator_name()
+	 * Applies the functional operator to given sentence context.
+	 * @returns Result of the application of this operator.
+	 * @param sc SentenceContext of the Sentence to apply the operator to.
+	 * @note The result is conciously marked as const, so a copy of operator data
+	 * is not created unless necessary.
+	 * @see apply() - equivalent method; the \link operator()() operator() \endlink allows
+	 * more convenient functional notation, however if you only have a pointer
+	 * you might prefer the apply method as shown below. The choice is yours.
+	 * \code
+	 * shared_ptr<const Bool> b;
+	 * b = op(sc);
+	 * // versus
+	 * b = op.apply(sc);
+	 * // or if you have a pointer...
+	 * b = (*op_ptr)(sc);
+	 * // versus
+	 * b = op_ptr->apply(sc);
+	 * \endcode
+	 * @see copy_apply() - method that creates and returns a copy of the result
+	 * for you to modify as you may see fit if you need it;
+	 * this is convenience method over having to create a copy yourself.
 	 */
-	virtual std::string to_raw_string() const {
-		return raw_operator_name();
-	}
+	boost::shared_ptr<const T> operator()(const SentenceContext& sc);
+
+	/**
+	 * Applies the functional operator to given sentence context.
+	 * @returns Result of the application of this operator.
+	 * @param sc SentenceContext of the Sentence to apply the operator to.
+	 * @note The result is conciously marked as const, so a copy of operator data
+	 * is not created unless necessary.
+	 * @see \link operator()() operator() \endlink - an equivalent of this method that allows for functional
+	 * notation, treating Operator directly as a function
+	 * @see copy_apply - method that creates and returns a copy of the result
+	 * for you to modify as you may see fit if you need it;
+	 * this is convenience method over having to create a copy yourself.
+	 */
+	boost::shared_ptr<const T> apply(const SentenceContext& sc);
+
+	/**
+	 * Applies the functional operator to given sentence context, returning pointer
+	 * to a mutable Value.
+	 * @returns Result of the application of this operator.
+	 * @param sc SentenceContext of the Sentence to apply the operator to.
+	 * @see \link operator()() operator() \endlink, apply - you may still be
+	 * better off using them if you expect to work on a raw value rather
+	 * than a pointer, as in e.g.
+	 * \code
+	 * StrSet s = *op(sc);
+	 * StrSet s2 = *op_ptr->apply(sc);
+	 * StrSet s3 = *(*op_ptr)(sc); // included for completeness
+	 * //versus
+	 * shared_ptr<StrSet> s_ptr = op.copy_apply(sc);
+	 * shared_ptr<StrSet> s_ptr2 = op_ptr->copy_apply(sc);
+	 * \endcode
+	 */
+	boost::shared_ptr<T> copy_apply(const SentenceContext& sc);
+
+	/**
+	 * Applies the functional operator to given sentence context.
+	 * @returns Result of the application, in terms of base type of Value.
+	 * @see \link operator()() operator() \endlink, apply - since you have
+	 * a concrete type at hand, you probably want to use one of these
+	 * two instead of this method that is inherited from FunctionalOperator
+	 */
+	boost::shared_ptr<const Value> base_apply(const SentenceContext& sc);
+
+	/**
+	 * Makes a copy of the Operator, having its own space for Variables.
+	 * This allows the copy to be run concurrently (otherwise methods
+	 * of this class are not thread-safe; concurrent executions
+	 * on the same object would share Variables so don't do that).
+	 * @returns A copy of the Operator, including copy of Variables' values.
+	 * @note The values of the Variables are copied as they are, which is
+	 * a usable feature. If that is not what you want, use clone_clean()
+	 * or call clean() when you need it.
+	 * @see clone_clean - a convenience version that returns a copy with
+	 * all Variables set to their default values.
+	 * @see clone_ptr - a version that returns a copy wrapped in a shared
+	 * pointer
+	 * @see clone_clean_ptr - a version that returns a copy wrapped
+	 * in a shared pointer, and also having its Variables cleaned.
+	 * @see \link Operator(const Operator&, bool) copy constructor \endlink -
+	 * another way to create a copy
+	 * @see \link operator=(const Operator&) operator= \endlink - assignment
+	 * operator, yet another way to create a copy.
+	 */
+	Operator clone() const;
+
+	/**
+	 * Makes a copy of the Operator, having its own space for Variables.
+	 * This allows the copy to be run concurrently (otherwise methods
+	 * of this class are not thread-safe; concurrent executions
+	 * on the same object would share Variables so don't do that).
+	 * All the Variables in the copy will have default values.
+	 * @returns A copy of the Operator with Variables that have default
+	 * values.
+	 * @see clone - a version that returns a copy without cleaning Variables.
+	 * @see clone_ptr - a version that returns a copy wrapped in a shared
+	 * pointer
+	 * @see clone_clean_ptr - a version that returns a copy wrapped
+	 * in a shared pointer, and also having its Variables cleaned.
+	 */
+	Operator clone_clean() const;
+
+	/**
+	 * @returns A copy of the expression, with values of the variables
+	 * copied as well.
+	 * @see clone_clean_ptr - convenience version that returns clean copy.
+	 */
+	boost::shared_ptr<Operator<T> > clone_ptr() const;
+
+	/**
+	 * @returns A copy of the expression, with values of the variables
+	 * set to their defaults.
+	 * @see clone_ptr - a version that keeps values of the variables.
+	 */
+	boost::shared_ptr<Operator<T> > clone_clean_ptr() const;
+
+	/**
+	 * Copy constructor, creates a copy with new set of values for
+	 * variables, allowing concurrent run of semantically same Operator;
+	 * running same physical Operator object is inherently not thread safe).
+	 * @param other - the Operator to copy.
+	 * @param clean - true if copy needs to have its variables
+	 * set to default values, false to keep the values; false is default
+	 */
+	Operator(const Operator& other, bool clean = false);
+
+	/**
+	 * Default constructor. Produces operator that returns default
+	 * value for given type.
+	 */
+	Operator();
+
+	/**
+	 * Assignment operator to create a workable copy of other Operator
+	 * (workable means it has a new set of values for variables, allowing
+	 * concurrent run of semantically same Operator; running same physical
+	 * Operator object is inherently not thread safe).
+	 * @note The values for variables are kept as in the original Operator.
+	 * @param other - Operator to copy
+	 * @returns A reference to the current object, after assignment.
+	 */
+	Operator& operator=(const Operator& other);
+
+	std::string to_string(const Corpus2::Tagset& tagset) const;
+
+	std::string to_raw_string() const;
+
+protected:
+	Operator* clone_internal() const;
+
+private:
+	boost::shared_ptr<Function<T> > function_body_;
 };
 
+//--- implementation details ---
+
+inline
+FunctionalOperator::FunctionalOperator(
+		const Variables &variables)
+	: ParsedExpression(variables)
+{
+}
+
+inline
+boost::shared_ptr<FunctionalOperator> FunctionalOperator::clone_ptr() const {
+	return boost::shared_ptr<FunctionalOperator>(clone_internal());
+}
+
+inline
+boost::shared_ptr<FunctionalOperator> FunctionalOperator::clone_clean_ptr() const {
+	boost::shared_ptr<FunctionalOperator> copy(clone_internal());
+	BOOST_ASSERT(copy);
+	copy->clean();
+	return copy;
+}
+
+template <class T> inline
+Operator<T>::Operator(
+		const boost::shared_ptr<Function<T> >& body,
+		const Variables &variables)
+	: FunctionalOperator(variables),
+	  function_body_(body)
+{
+	BOOST_ASSERT(body);
+}
+
+template <class T> inline
+boost::shared_ptr<const T> Operator<T>::apply(const SentenceContext &sc) {
+	return function_body_->apply(FunExecContext(sc, variables_));
+}
+
+template <class T> inline
+boost::shared_ptr<const T> Operator<T>::operator()(const SentenceContext &sc) {
+	return apply(sc);
+}
+
+template <class T> inline
+boost::shared_ptr<T> Operator<T>::copy_apply(const SentenceContext &sc) {
+	return boost::make_shared<T>(*apply(sc));
+}
+
+template <class T> inline
+boost::shared_ptr<const Value> Operator<T>::base_apply(const SentenceContext &sc) {
+	return apply(sc);
+}
+
+template <class T> inline
+Operator<T>* Operator<T>::clone_internal() const {
+	return new Operator<T>(function_body_, *variables_);
+}
+
+template <class T> inline
+Operator<T>::Operator(const Operator &other, bool clean)
+	: FunctionalOperator(*other.variables_),
+	  function_body_(other.function_body_)
+{
+	BOOST_ASSERT(function_body_);
+	if(clean) {
+		this->clean();
+	}
+}
+
+template <class T> inline
+Operator<T> Operator<T>::clone() const {
+	return *this;
+}
+
+template <class T> inline
+Operator<T> Operator<T>::clone_clean() const {
+	return Operator(*this, true);
+}
+
+template <class T> inline
+Operator<T>& Operator<T>::operator=(const Operator& other) {
+	BOOST_ASSERT(other.function_body_);
+	BOOST_ASSERT(other.variables_);
+	function_body_.reset(other.function_body_);
+	variables_.reset(new Variables(other.variables_));
+	return *this;
+}
+
+namespace detail {
+
+template<class T>
+static boost::shared_ptr<Function<T> > DefaultFunction() {
+	static boost::shared_ptr<Function<T> > default_fun(new Constant<T>((T())));
+	return default_fun;
+}
+
+}
+
+template <class T> inline
+Operator<T>::Operator()
+	: FunctionalOperator((Variables())),
+	  function_body_(detail::DefaultFunction<T>())
+{
+	BOOST_ASSERT(function_body_);
+}
+
+template <class T> inline
+boost::shared_ptr<Operator<T> > Operator<T>::clone_ptr() const {
+	return boost::shared_ptr<Operator<T> >(clone_internal());
+}
+
+template <class T> inline
+boost::shared_ptr<Operator<T> > Operator<T>::clone_clean_ptr() const {
+	boost::shared_ptr<Operator<T> > copy(clone_internal());
+	BOOST_ASSERT(copy);
+	copy->clean();
+	return copy;
+}
+
+template <class T> inline
+std::string Operator<T>::to_string(const Corpus2::Tagset &tagset) const {
+	return function_body_->to_string(tagset);
+}
+
+template <class T> inline
+std::string Operator<T>::to_raw_string() const {
+	return function_body_->to_raw_string();
+}
+
 } /* end ns Wccl */
 
 #endif // LIBWCCL_OPS_OPERATOR_H