Можно и так. Но перегрузка операторов имеет одно неприятное свойство: не всегда прогнозируемый порядок вызова, а это как раз минус: в монадном контексте порядок вычисления должен быть строго последовательным.
Я тоже сначала сделал перегрузку >>, |, *, и вот тут то меня и подвел приоритет операций. В вашем варианте перегружен только пайп, но даже он уже может быть как лево-, так и правосторонним.
Каррированная функция нескольких параметров представляет собой функцию одного параметра, возвращающую функцию одного параметра, возвращающую функцию одного параметра… Самая глубоко вложенная функция принимает последний параметр и возвращает результат.
При частичном применении можно задать какие-либо параметры, не обязательно первые, и в итоге получится функция от оставшихся параметров, которая опять может быть частично применена, а может и не быть.
Спасибо большое за информацию. Похоже key вычисляется один на элемент в первом проходе, а далее сортировка одних лишь ключей происходит, а cmp вызывается многократно для каждого конкретного элемента при сравнении его с другими.
Не знал, спасибо большое за информацию. Как раз подумывал замеры провести. Похоже key вычисляется один на элемент в первом проходе, а далее сортировка одних лишь ключей происходит, а cmp вызывается многократно для каждого конкретного элемента при сравнении его с другими.
Тут сказывается замороженный синтаксис Python — ничего нового не добавишь, только перегрузка и остается ))
А в вашем примере можно и не перегружать пайп, даже читабельнее будет:
Только тут функции идут в порядке их применения, а не в обратном порядке, как в композиции. Здесь происходит «проталкивание» данных через последовательность обработчиков. Порядок применения функций, само собой, можно и развернуть.
Есть у моего способа сортировки папа преимуществ:
1) если для сравниваемых пар вторые элементы уже позволяют определить порядок, первые не будут сравниваться, В варианте с key, ключ-пара будет создаваться в любом случае.
2) получение ключа каждый раз, это создание/«уборка» нового объекта, поэтому накладные расходы всё равно будут.
самое интересное, что два ключа внутри sort/sorted, скорее всего, все равно «скармливаются» функции cmp — она определяет порядок следования элементов ))
Придумал пример, немного синтетический, правда, того случая, когда cmp не применишь, по крайней мере в лоб.
Задача: нужно распределить числа в массиве по группам отрицательные, ноль(ноли) и положительные.
key вполне работает.
>>> import random
>>> l = [x - 10 for x in xrange(20)]
>>> random.shuffle(l)
>>> l
[7, 8, -10, -9, 3, 0, 4, -5, -1, 6, -7, -3, -4, -8, 2, 9, -6, -2, 5, 1]
>>> sign = lambda x: -1 if x < 0 else (0 if x == 0 else 1)
>>> sorted(l, key=sign)
[-10, -9, -5, -1, -7, -3, -4, -8, -6, -2, 0, 7, 8, 3, 4, 6, 2, 9, 5, 1]
Интересно? Могу написать последовательно, начиная с функторов, с примерами. Есть желание адаптировать «Learn you a Haskell for great Good», уже в Python-ключе и для императивщиков
Особенно, примеры и последовательность подачи материала удачны.
Последовательность: Maybe, IO (как magic-штуки в конкретных задачах) -> функторы -> аппликативные функторы -> монады. В процессе подачи материала та же Maybe сама вырисовывается и пишется с нуля: вот тут то и приходит понимание
Тут вы правы. Скорректировал. В данном случае именно частичное применение, с замыканием части параметров и возвратом функции, принимающей оставшиеся. Каррирование (нормальное) в Python страшновато выглядит.
Стандартное поведение при сравнении списков/кортежей:
(a1, b1) > (a2, b2) если a1 > a2, или b1 > b2 при a1 = a2
[::-1] разворачивает пары задом-наперед, чтобы сравнивались сначала вторые элементы
У key и cmp смысл разный: cmp позволяет нам сравнивать элементы, в то время как key дает нам возможность предоставить ключ для сортировки. Первый случай гибче, но не так часто нужен.
Я тоже сначала сделал перегрузку >>, |, *, и вот тут то меня и подвел приоритет операций. В вашем варианте перегружен только пайп, но даже он уже может быть как лево-, так и правосторонним.
При частичном применении можно задать какие-либо параметры, не обязательно первые, и в итоге получится функция от оставшихся параметров, которая опять может быть частично применена, а может и не быть.
key = lambda obj: (obj.age, -obj.iq, obj.weight)
А в вашем примере можно и не перегружать пайп, даже читабельнее будет:
Только тут функции идут в порядке их применения, а не в обратном порядке, как в композиции. Здесь происходит «проталкивание» данных через последовательность обработчиков. Порядок применения функций, само собой, можно и развернуть.
1) если для сравниваемых пар вторые элементы уже позволяют определить порядок, первые не будут сравниваться, В варианте с key, ключ-пара будет создаваться в любом случае.
2) получение ключа каждый раз, это создание/«уборка» нового объекта, поэтому накладные расходы всё равно будут.
Задача: нужно распределить числа в массиве по группам отрицательные, ноль(ноли) и положительные.
key вполне работает.
Причем порядок чисел внутри групп не поменялся!
Последовательность: Maybe, IO (как magic-штуки в конкретных задачах) -> функторы -> аппликативные функторы -> монады. В процессе подачи материала та же Maybe сама вырисовывается и пишется с нуля: вот тут то и приходит понимание
(a1, b1) > (a2, b2) если a1 > a2, или b1 > b2 при a1 = a2
[::-1] разворачивает пары задом-наперед, чтобы сравнивались сначала вторые элементы
К примеру, нужно сортировать список пар сначала по второму элементу:
ИМХО, весьма наглядно: для сравнения (cmp) пар, нужно сравнить (cmp) вторые элементы, а потом сравнить (cmp) первые.