<commit_before>import operator

from tryp import List


def format_funcall(fun, args, kwargs):
    from tryp import Map
    kw = Map(kwargs).map2('{}={!r}'.format)
    a = list(map(repr, args)) + list(kw)
    args_fmt = ', '.join(a)
    return '{}({})'.format(fun, args_fmt)


class AnonCallable:

    def __call__(self, obj):
        return obj


class AnonGetter(AnonCallable):

    def __init__(self, pre, name: str) -> None:
        self.pre = pre
        self.name = name

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, self.name)

    def __call__(self, obj):
        pre = self.pre(obj)
        if not hasattr(pre, self.name):
            raise AttributeError(
                '{!r} has no method \'{}\' -> {}'.format(obj, self.name, self))
        return self._dispatch(getattr(pre, self.name))

    def _dispatch(self, obj):
        return obj


class AnonFunc(AnonGetter):

    def __init__(self, pre: 'AnonFunc', name: str, a, kw) -> None:
        super().__init__(pre, name)
        self.a = a
        self.kw = kw

    def _dispatch(self, obj):
        return obj(*self.a, **self.kw)

    def __getattr__(self, name):
        return MethodRef(self, name)

    def __repr__(self):
        return '{!r}.{}'.format(self.pre,
                                format_funcall(self.name, self.a, self.kw))


class MethodRef:

    def __init__(self, pre: AnonFunc, name: str) -> None:
        self.pre = pre
        self.name = name

    def __call__(self, *a, **kw):
        return AnonFunc(self.pre, self.name, a, kw)

    def __getattr__(self, name):
        pre = AnonGetter(self.pre, self.name)
        return MethodRef(pre, name)

    def __repr__(self):
        return '__.{}'.format(self.name)


class IdAnonFunc:

    def __call__(self, obj):
        return obj

    def __repr__(self):
        return '__'


class MethodLambda:

    def __getattr__(self, name):
        return MethodRef(IdAnonFunc(), name)

__ = MethodLambda()


class ComplexLambda:

    def __init__(self, func, *a, **kw) -> None:
        self.func = func
        self.args = List.wrap(a)
        self.kwargs = kw

    def __call__(self, *a, **kw):
        sub_a = self._substitute(List.wrap(a))
        return self.func(*sub_a, **kw)

    def _substitute(self, args):
        def errmsg():
            return 'too few arguments for lambda "{}": {}'.format(self, args)
        def is_lambda(arg):
            return arg is _ or isinstance(arg, AnonCallable)
        def go(z, arg):
            def transform(value):
                return arg(value) if isinstance(arg, AnonCallable) else value
            r, a = z
            new, rest = (a.detach_head.get_or_fail(errmsg()) if is_lambda(arg)
                         else (arg, a))
            return r.cat(transform(new)), rest
        return self.args.fold_left((List(), args))(go)[0]

    def __getattr__(self, name):
        return MethodRef(self, name)
<commit_msg>assert that `ComplexLambda` arg is callable<commit_after>import operator

from tryp import List


def format_funcall(fun, args, kwargs):
    from tryp import Map
    kw = Map(kwargs).map2('{}={!r}'.format)
    a = list(map(repr, args)) + list(kw)
    args_fmt = ', '.join(a)
    return '{}({})'.format(fun, args_fmt)


class AnonCallable:

    def __call__(self, obj):
        return obj


class AnonGetter(AnonCallable):

    def __init__(self, pre, name: str) -> None:
        self.pre = pre
        self.name = name

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, self.name)

    def __call__(self, obj):
        pre = self.pre(obj)
        if not hasattr(pre, self.name):
            raise AttributeError(
                '{!r} has no method \'{}\' -> {}'.format(obj, self.name, self))
        return self._dispatch(getattr(pre, self.name))

    def _dispatch(self, obj):
        return obj


class AnonFunc(AnonGetter):

    def __init__(self, pre: 'AnonFunc', name: str, a, kw) -> None:
        super().__init__(pre, name)
        self.a = a
        self.kw = kw

    def _dispatch(self, obj):
        return obj(*self.a, **self.kw)

    def __getattr__(self, name):
        return MethodRef(self, name)

    def __repr__(self):
        return '{!r}.{}'.format(self.pre,
                                format_funcall(self.name, self.a, self.kw))


class MethodRef:

    def __init__(self, pre: AnonFunc, name: str) -> None:
        self.pre = pre
        self.name = name

    def __call__(self, *a, **kw):
        return AnonFunc(self.pre, self.name, a, kw)

    def __getattr__(self, name):
        pre = AnonGetter(self.pre, self.name)
        return MethodRef(pre, name)

    def __repr__(self):
        return '__.{}'.format(self.name)


class IdAnonFunc:

    def __call__(self, obj):
        return obj

    def __repr__(self):
        return '__'


class MethodLambda:

    def __getattr__(self, name):
        return MethodRef(IdAnonFunc(), name)

__ = MethodLambda()


class ComplexLambda:

    def __init__(self, func, *a, **kw) -> None:
        assert callable(func), 'ComplexLambda: {} is not callable'.format(func)
        self.func = func
        self.args = List.wrap(a)
        self.kwargs = kw

    def __call__(self, *a, **kw):
        sub_a = self._substitute(List.wrap(a))
        return self.func(*sub_a, **kw)

    def _substitute(self, args):
        def errmsg():
            return 'too few arguments for lambda "{}": {}'.format(self, args)
        def is_lambda(arg):
            return arg is _ or isinstance(arg, AnonCallable)
        def go(z, arg):
            def transform(value):
                return arg(value) if isinstance(arg, AnonCallable) else value
            r, a = z
            new, rest = (a.detach_head.get_or_fail(errmsg()) if is_lambda(arg)
                         else (arg, a))
            return r.cat(transform(new)), rest
        return self.args.fold_left((List(), args))(go)[0]

    def __getattr__(self, name):
        return MethodRef(self, name)

{'fraction_non_alphanumeric': 0.1374874707651186, 'fraction_numerical': 0.0006682258603407952, 'mean_word_length': 2.268013100436681, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, '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': '3893570', 'n_tokens_mistral': 1984, 'n_tokens_neox': 1923, 'n_words': 499}