Comments 39
Буквально, свежак:
«Итак, вы можете писать что угодно на чём угодно, в смысле программирования, и монады у вас там будут независимо от того, в курсе вы или нет. „
http://ivan-gandhi.livejournal.com/1884945.html
«Итак, вы можете писать что угодно на чём угодно, в смысле программирования, и монады у вас там будут независимо от того, в курсе вы или нет. „
http://ivan-gandhi.livejournal.com/1884945.html
+3
Каррирование: docs.python.org/library/functools.html#functools.partial
0
Каррирование != частичное применение
0
Тут вы правы. Скорректировал. В данном случае именно частичное применение, с замыканием части параметров и возвратом функции, принимающей оставшиеся. Каррирование (нормальное) в Python страшновато выглядит.
0
Если не сложно, объясните в чем разница.
0
Думаю в том, что каррирование можно применять много раз подряд пока не наберется требуемое кол-во аргументов. Частичное применение работает до первого раза.
В питоне без хаков нельзя узнать сколько аргументов требуется функции.
В питоне без хаков нельзя узнать сколько аргументов требуется функции.
-1
можно:
f.func_code.co_argcount
0
А вот за это спасибо большое! Единственно, неудобно узнавать кол-во параметров у метода — self тоже считается.
0
unbound-методы действительно принимают на один аргумент больше (+self), чем соответствующие им bound-методы:
A.m — unbound-метод, принимающий 4 аргумента (self, a, b, c)
Для а = A(), A().m — это bound-метод, принимающий 3 аргумента (a, b, c), по-сути тоже самое что
Проверить метод на привязанность к конкретному объекту можно через
class A(object):
def m(self, a, b, c):
pass
A.m — unbound-метод, принимающий 4 аргумента (self, a, b, c)
Для а = A(), A().m — это bound-метод, принимающий 3 аргумента (a, b, c), по-сути тоже самое что
partial(A.m, a)
Проверить метод на привязанность к конкретному объекту можно через
method.im_self is None
0
Каррированная функция нескольких параметров представляет собой функцию одного параметра, возвращающую функцию одного параметра, возвращающую функцию одного параметра… Самая глубоко вложенная функция принимает последний параметр и возвращает результат.
При частичном применении можно задать какие-либо параметры, не обязательно первые, и в итоге получится функция от оставшихся параметров, которая опять может быть частично применена, а может и не быть.
При частичном применении можно задать какие-либо параметры, не обязательно первые, и в итоге получится функция от оставшихся параметров, которая опять может быть частично применена, а может и не быть.
+2
ну так получается что каррирование — частный случай частичного применения.
или каррирование не до конца — несчитово?
или каррирование не до конца — несчитово?
0
Каррированная функция, это всегда функция одного аргумента, причем всегда первого. Тут ноги растут из лямбда-исчисления, может я и не смогу правильно объяснить — моё понимание, скорее, интуитивно.
Частичное применение возможно везде, где есть замыкание и функции, как объекты первого порядка.
При частичном применении мы замыкаем часть параметров и возвращаем обычную функцию, просто с меньшим кол-вом параметров.
Каррированная функция каррирована насквозь:
f = lambda x: lambda y: lambda z: (x+y)*z
Такую функцию можно вызывать(для получения конечного результата) только так:
f(1)(2)(3)
На Python это некрасиво выглядит, а вот в Haskell всё отлично — там все функции каррированы всегда, и вызов выглядит проще:
f 1 2 3 == (((f 1) 2) 3)
Частичное применение возможно везде, где есть замыкание и функции, как объекты первого порядка.
При частичном применении мы замыкаем часть параметров и возвращаем обычную функцию, просто с меньшим кол-вом параметров.
Каррированная функция каррирована насквозь:
f = lambda x: lambda y: lambda z: (x+y)*z
Такую функцию можно вызывать(для получения конечного результата) только так:
f(1)(2)(3)
На Python это некрасиво выглядит, а вот в Haskell всё отлично — там все функции каррированы всегда, и вызов выглядит проще:
f 1 2 3 == (((f 1) 2) 3)
0
Недавно наткнулся на похожее для Java — codereview.stackexchange.com/questions/8055/java-monad-implementation
0
Для Java есть google-guava. Там есть класс Optional, он как раз Maybe-монаду и имплементирует.
code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained
code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained
+2
Книга действительно отличная. Впечатляет, что написал ее 23-летний словенец (или как называется житель Словении).
+1
Автор сразу начал реализовывать, но так и не написал, что же представляют из себя эти загадочные монады :)
+5
Интересно? Могу написать последовательно, начиная с функторов, с примерами. Есть желание адаптировать «Learn you a Haskell for great Good», уже в Python-ключе и для императивщиков
+6
Про то, что же они из себя представляют понаписано уже море статей. В том числе на хабре.
Статьи танцуют и от теории категорий, и от монадических значений, и от пирмеров монад «в реальной жизни» — яснее от этого не становится нифигашеньки.
Автор пошёл альтернативным путём — и это хорошо!
Статьи танцуют и от теории категорий, и от монадических значений, и от пирмеров монад «в реальной жизни» — яснее от этого не становится нифигашеньки.
Автор пошёл альтернативным путём — и это хорошо!
0
А я как-то делал композицию функций на Питоне. Чтобы можно было соединять функции оператором | и писать что-то вроде:
Получается прикольно, но использовать такое, конечно, не особенно станешь.
','.join(map(str | int, [4.5, 6.7, 8.02]))
Получается прикольно, но использовать такое, конечно, не особенно станешь.
0
Тут сказывается замороженный синтаксис Python — ничего нового не добавишь, только перегрузка и остается ))
А в вашем примере можно и не перегружать пайп, даже читабельнее будет:
Только тут функции идут в порядке их применения, а не в обратном порядке, как в композиции. Здесь происходит «проталкивание» данных через последовательность обработчиков. Порядок применения функций, само собой, можно и развернуть.
А в вашем примере можно и не перегружать пайп, даже читабельнее будет:
def push_through(*funcs):
def inner(value):
return reduce(lambda x, f: f(x), funcs, value)
return inner
print ','.join(map(push_through(int, str), [4.5, 6.7, 8.02]))
Только тут функции идут в порядке их применения, а не в обратном порядке, как в композиции. Здесь происходит «проталкивание» данных через последовательность обработчиков. Порядок применения функций, само собой, можно и развернуть.
0
Методом обёртывания функций?
0
А есть другой способ?
0
Это же не обёртывание:
sequence = lambda *funcs: lambda x: reduce(lambda xx, f: f(xx), funcs, x)
map(sequence(int, str), [1.0, 2.5, 3.7])
Тут вместо композиции свертка с применением списка функций к значению. Результат тот же будет
sequence = lambda *funcs: lambda x: reduce(lambda xx, f: f(xx), funcs, x)
map(sequence(int, str), [1.0, 2.5, 3.7])
Тут вместо композиции свертка с применением списка функций к значению. Результат тот же будет
0
Обертывание нужно для этого: str | int
0
В этом случае нужно. Причем, случай крайний — для встроенных функций просто так оператор не перегрузишь, и декоратор не прикрутишь. Тут только так:
или
или хотя бы
Combinable(int) | str
или
str | Combinable(int)
или хотя бы
str | int | Combinable()
0
«result must be MayBe» — это пять! это по-хаскелевски! :)
+1
По-моему на Хабре нехватает хорошего туториала, «на пальцах» объясняющего, что такое монады, моноиды, функторы, аппликативные функторы и остальные понятия и принципы из этой области. Есть, конечно, Википедия, но по-моему там не достаточно понятно. Вот, например, что такое MayBe я прекрасно понимаю и активно использую (точнее Option в Scala), а что такое монада в принципе и всё остальное — нет.
0
В замечательной книге «Learn You a Haskell for Great Good!» отлично всё написано про монады, моноиды, функторы. Причем описание идёт на практических примерах — без непосредственного введения термина, скажем «монада», но с постепенным «выкристализовыванием» чего-то простого, понятного, а главное — полезного. А потом это «что-то» и оказывается монадой ))
Я думаю, не стоит цитировать книгу на Хабре — она есть в свободном доступе (по крайней мере английская версия). Своими словами можно объяснить, но лучше чем в книге у меня лично вряд ли получится…
P.S. Option в Scala, это, всё таки, просто АТД, в который удобно завернуть результат вычисления, способного неудасться. И всё. Синтаксической поддержки нет (удобной, хотя бы как в Haskell), вычисления в контексте монадном почти никто не делает…
Если уж монады в Scala искать, так лучше обратить внимание на for/yield — вполне себе, монада списка сдобренная нужным кол-вом синтаксического сахара.
P.P.S. Объяснение «на пальцах» выше указанным терминам можно дать в практическом ключе, а фундамент находится в теории категорий, которую сходу на пальцах не объяснишь…
Я думаю, не стоит цитировать книгу на Хабре — она есть в свободном доступе (по крайней мере английская версия). Своими словами можно объяснить, но лучше чем в книге у меня лично вряд ли получится…
P.S. Option в Scala, это, всё таки, просто АТД, в который удобно завернуть результат вычисления, способного неудасться. И всё. Синтаксической поддержки нет (удобной, хотя бы как в Haskell), вычисления в контексте монадном почти никто не делает…
Если уж монады в Scala искать, так лучше обратить внимание на for/yield — вполне себе, монада списка сдобренная нужным кол-вом синтаксического сахара.
P.P.S. Объяснение «на пальцах» выше указанным терминам можно дать в практическом ключе, а фундамент находится в теории категорий, которую сходу на пальцах не объяснишь…
0
а фундамент находится в теории категорий, которую сходу на пальцах не объяснишь
Опыт многократно показал, что почти любую академическую заумь можно объяснить так, чтобы было понятно даже детям. Было бы желание и достаточное понимание у самого объясняющего. Ждём «теорию категорий для чайников» на Хабре… :-)
Если уж монады в Scala искать, так лучше обратить внимание на for/yield — вполне себе, монада списка сдобренная нужным кол-вом синтаксического сахара.
Так и не понял зачем нужен for/yield когда есть map. Кажется только один раз мне пришлось использовать for/yield и то я уже не помню почему.
0
В себе пока не чувствую сил теоркат объяснять, увы…
А for/yield это не просто map, это скорее filter/map/concat в одном флаконе:
А for/yield это не просто map, это скорее filter/map/concat в одном флаконе:
class Book(title: String, authors: List[String])
// наименования книг, написанных Кнутом
for (b <- books; a <- b.authors if a startsWith "Knuth,") yield b.title
// авторы, написавшие более чем одну книгу
{ for {
b1 <- books
b2 <- books
if b1 != b2
a1 <- b1.authors
a2 <- b2.authors
if a1 == a2
} yield a1
}.distinct
+1
Sign up to leave a comment.
Для тех, кто хочет странного: монады в Python