LINUX.ORG.RU

[питон] А как записать многострочную лямбду?

 


0

1

Сегодня на улице прекрасная погода. Хорошее настроение. Но, увы, нужно переписать на питоне один кусок кода с многострочной лямбдой. Встречается часто. Есть какой-нибудь способ? По силу такое творению Гвидо? :)

Вот, на хаскеле его шаблон выглядит таким образом, где (>>=) - это просто бинарный оператор:

f m1 m2 m3 =
    m1 >>= \x1 ->
    m2 >>= \x2 ->
    m3 >>= \x3 ->
    return (x1, x2, x3)

Если не пользоваться стандартными функциями, то тоже самое можно было бы написать по-другому:

f m1 m2 m3 = do
    x1 <- m1
    x2 <- m2
    x3 <- m3
    return (x1, x2, x3)

Почти то же самое на лиспе (CL) записывается легко, где with-puper - особо определяемый макрос с макролетами let! и unit:

(defun f (m1 m2 m3)
  (with-puper
     (let! ((x1 m1)
            (x2 m2)
            (x3 m3))
        (unit (list x1 x2 x3)))))

На F# тоже очень просто:

let f m1 m2 m3 = puper {
    let! x1 = m1
    let! x2 = m2
    let! x3 = m3
    return (x1, x2, x3)
}

По сути это синтаксический сахар вокруг следующего кода, где опять же многострочная лямбда:

let f m1 m2 m3 =
  puper.Delay (fun () ->
    puper.Bind (m1, fun x1 ->
      puper.Bind (m2, fun x2 ->
        puper.Bind (m3, fun x3 ->
          puper.Return ((x1, x2, x3))))))

Пожалуй, проще всего ориентироваться на последний пример. Я даже боюсь представить себе, как это будет выглядеть на питоне, если попытаться засунуть все в одну строку, как того требует его конструкция lambda... Или есть другой способ?

★★★★★

Если вам нужны многострочные лямбды, возможно вы просто выбрали не тот ЯП.

Нет, это не значит, что на питоне это невозможно написать. Это значит, что на питоне нужно писать по-другому.

Davidov ★★★★
()

а там нельзя написать какую нибудь ридер-процедуру, которая вернёт из много-строчного выражения одно-строчное?) мне просто интересно))

pseudo-cat ★★★
()

Рубидиевые треды ЛОР

anonymous
()

Выбери другой язык, или перепиши как функцию, внутри питоновой лямбды нельзя не только использовать несколько строк но и сделать аналог банального let, тоесть lambda x: a=x работать небудет.

cvb
()
Ответ на: комментарий от balodja

Питонолямбды не обладают лексическим контекстом.

Почему не обладают? Помоему обладают

In [1]: def test2 ():
   ...:         x=1
   ...:     return lambda : x
   ...: 

In [2]: z = test2()

In [3]: print z()
------> print(z())
1

Но лямбды в нем таки говно, например на return lambda s: print x питон уже ругался, в общем лучше их не трогать.

cvb
()
Ответ на: комментарий от cvb

Но лямбды в нем таки говно, например на return lambda s: print x питон уже ругался, в общем лучше их не трогать.

>>> def test2():
...     x = 'boo'
...     return lambda s: print(x)
... 
>>> test2()('s')
boo
>>>

А?

rival ★★
()

> Но, увы, нужно переписать на питоне один кусок кода с многострочной лямбдой.

Началник-зверь заставляют тебя с хаскела на питон переписывать код?)

Alesh
()
Ответ на: комментарий от rival

А?

Ага

In [1]: def test2 ():
   ...:     x=1
   ...:     return lambda : print(x)
------------------------------------------------------------
   File "<ipython console>", line 3
     return lambda : print(x)
                         ^
SyntaxError: invalid syntax
Python 2.6.4 (r264:75706, Dec 7 2009, 18:43:55)

Фаза луны не та?

cvb
()
Ответ на: комментарий от cvb

> Фаза луны не та?

Нет, версия питона не та:

Python 3.1.2 (r312:79147, Mar 29 2010, 22:27:41)

rival ★★
()
Ответ на: комментарий от dave

Кстати, через ap можно здорово сократить лямбды в данном случае.

dave ★★★★★
() автор топика
Ответ на: комментарий от dave

я думал, ты знаешь

я про представленный код

jtootf ★★★★★
()

на Europython2008 Гвидо задали вопрос: что сделано в питоне плохо и не получается починить. ответ был «многострочные лямбды» :)

Pi ★★★★★
()

Прекрасно работает: [code=python] from operator import add

bindl = lambda xs, f: reduce(add, map(f, xs))

print \ bindl([1, 2], lambda x: bindl([3, 4], lambda y: bindl([5, 6], lambda z: [x * y * z]))) [/code]

tarc
()

Пардон.

from operator import add

bindl = lambda xs, f: reduce(add, map(f, xs))

print \
    bindl([1, 2], lambda x:
    bindl([3, 4], lambda y:
    bindl([5, 6], lambda z:
    [x * y * z])))
tarc
()
Ответ на: комментарий от dave
from operator import add
 
bindl = lambda xs, f: reduce(add, map(f, xs))  
let = lambda x, f: f(x)
  
print \   
    bindl([1, 2], lambda x:
    let  ([3, 4], lambda ys:
    bindl(ys,     lambda y:
    bindl([5, 6], lambda z:    
    [x * y * z]))))

Ну что, как всегда за неимением других аргументов будем придираться к пробелам? :)

tarc
()
Ответ на: комментарий от tarc

Ну, да. Прием, описанный в SICP. A несколько вподряд идущих statement тоже имитировать через фиктивные lambda? И получим блестящую производительность на выходе :) Но все равно интересно. Узнал, что лямбда перестала таки быть однострочной. Есть какой-то прогресс.

dave ★★★★★
() автор топика
Ответ на: комментарий от tarc

Ужас, летящий на крыльях ночи

from operator import add 
  
bindl = lambda xs, f: reduce(add, map(f, xs))   
let = lambda x, f: f(x) 
   
print \    
    bindl([1, 2], lambda x: 
    let  ([3, 4], lambda ys: 
    bindl(ys,     lambda y: 
    bindl([5, 6], lambda z:     
    [x * y * z])))) 
yoghurt ★★★★★
()
Ответ на: комментарий от dave

> Прием, описанный в SICP.

А ты надеялся что я тебе на ушах спляшу? Ну извини.

A несколько вподряд идущих statement тоже имитировать через фиктивные lambda? И получим блестящую производительность на выходе :)

Можно воспользоваться паттерн-матчингом let((1,2), lambda (x,y): ...), если ты об этом. А вообще, обладая таким богатым опытом программирования в функциональной парадигме к тормозам пора бы привыкнуть.

tarc
()
Ответ на: комментарий от tarc

> А вообще, обладая таким богатым опытом программирования в функциональной парадигме к тормозам пора бы привыкнуть.

Молодец, переиграл :)

dave ★★★★★
() автор топика
Ответ на: комментарий от balodja

> Ну вроде многострочная лямбда — вполне естественное желание.

Тот пример который был приподнесён ТС типа для переписывания на Питон, чисто высосанная из пальца тема для «Рубидиевого» треда. Тарку +500 - быстро и грамотно перевел его в тему «Очередной облом функциональщиков потролить питон» ;)

Alesh
()
Ответ на: комментарий от jreznot

> Может всё таки топикстартер напишет функцию отдельно ???

Это невозможно. Нужны замыкания. Где это может быть надо? Например, для того, чтобы переписать часть моей библиотеки моделирования с F# на питон. Но только часть. В питоне нет аналога вычислительных выражений. Без этого eDSL получится хромой. Но как бы то ни было, базовая часть eDSL для моделирования может быть перенесена. Правда, в питоне невозможно определить переменные взаимно-рекурсивного как в F#. Такая фича заметно бы упростила использование моего eDSL. Но, пожалуй, для топика хватит и лямбд.

Кстати, присваивание можно таки вкючить внутрь лямбды. По сути такой фичи нет даже в F#. Но обходится очень просто. Создается ссылка, а на нее уже распространяется замыкание. В общем, через окамловскую ссылку ref. На питоне имитируется легко, но костыльно.

dave ★★★★★
() автор топика
Ответ на: комментарий от dave

Наверное, невозможного в этом все таки нет, но это - такая трабла переводить лямбды в обычные функции! Нет уж, спасибо! Ешьте сами :)

dave ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.