LINUX.ORG.RU

rust, ФП и lifetime

 


1

5

Господа знатоки, подскажите пожалуйста, что именно с lifetime в этом коде не так, что компилер не хочет его кушать и как это можно исправить сохранив суть.

fn curry<A,B,C>(f : Box<Fn(A,B) -> C>, a : A) -> Box<Fn(B) -> C> {
    Box::new(move|b : B| {f(a,b)})
}

★★★★★

тебеж конпелятор ясно говорит, что A недостаточно живет.

anonymous
()

rust это латынь

anonymous
()

А вообще абсолютно дебильная ошибка. Особенно в момент, когда совершенно не ясно что будут за типы эти ABC. Какой нах лайфтайм у скопированного инта?

anonymous
()

Две проблемы:

1. Box<Fn(A,B)->C> по умолчанию имеет время жизни 'static. Поэтому нужно сделать A: 'static, B: 'static, C: 'static или указать время жизни для типов и boxed closures <A: 'a ...>(f: Box<...> + 'a, ...) -> Box<...> + 'a

2. Для типа A не указан trait bound Copy, поэтому a перемещается внутрь замыкания f в выражении f(a, b), из-за этого невозможно вызвать возвращаемое замыкание несколько раз. То есть нужно заменить возвращаемый тип на Box<FnOnce(B)->C>, или указать, что A реализует трейт Copy, или передавать a в замыкание по ссылке.

Один из вариантов:

fn curry<A: Copy + 'static, B: 'static, C: 'static>(f : Box<Fn(A,B) -> C>, a : A) -> Box<Fn(B) -> C> {
    Box::new(move|b : B| {f(a,b)})
}

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

да нашел уже

let c = curry( Box::new(|x:u32, y:u32| { x + y }), 10 as u32 );
let r = c(10); //  r == 20

капец наркомания.

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

Мне нужно построить функцию и выдать. Пример с каррированием самый простой, что в голову пришел. Суть в том, что в качестве одного из аргументов функция и на выходе функция, типы шаблон и время жизни не 'static. Вот что мне нужно.

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

Спасибо. А как правильно указать время жизни руками? Плюсы компилеру не нравятся.

error: expected one of `!`, `::`, `where`, or `{`, found `+`
 --> <anon>:1:98
1 |> fn curry<A : Copy + 'a,B : 'a,C : 'a>(f : Box<Fn(A,B) -> C> + 'a, a : A + 'a) -> Box<Fn(B) -> C> + 'a {
  |>                                                                                                  ^

error: aborting due to previous error

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

curry<'r, A: Copy + 'r, B: 'r, C: 'r>

но все равно не сработает. Box один пес живет в 'static

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

А там точно нужен Copy?

fn curry<A: 'static, B: 'static, C: 'static>(f : Box<Fn(A,B) -> C>, a : A) -> Box<Fn(B) -> C> {
    Box::new(move|b : B| {f(a,b)})
}

но везде 'static - это же неспортивно и не то, что нужно.

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

Да ладно

error: borrowed value does not live long enough
 --> <anon>:2:6
2 |>     &move|b : B| {f(*a,b)}
  |>      ^^^^^^^^^^^^^^^^^^^^^
note: reference must be valid for the lifetime 'x as defined on the block at 1:72...
 --> <anon>:1:73
1 |> fn curry<'x, A, B, C>(f : &'x Fn(A,B) -> C, a :&'x A) -> &'x Fn(B) -> C {
  |>                                                                         ^
note: ...but borrowed value is only valid for the block at 1:72
 --> <anon>:1:73
1 |> fn curry<'x, A, B, C>(f : &'x Fn(A,B) -> C, a :&'x A) -> &'x Fn(B) -> C {
  |>                                                                         ^

error: cannot move out of borrowed content [--explain E0507]
 --> <anon>:2:21
2 |>     &move|b : B| {f(*a,b)}
  |>                     ^^ cannot move out of borrowed content

error: aborting due to 2 previous errors

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

Функция не скомпилируется. Проверка до неё похоже не доходит без main.

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

Вернуть ссылку на локальное замыкание никак не получится, только боксинг, или impl Fn(), когда доделают.

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

а на этом и не пишут ничего сложнее хеловордов*. Ну и перед посонами, опять же, похипстовать и понты поколотить.

* есть еще, правда, мифический servo, который, говорят, сложнее хеловорда, но видевший его анонимус утверждает, что простой пример с WebKit работает сильно лучше и сильно стабильнее.

anonymous
()

Отличная шутка, этот ваш Rust.

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

Нормально можно писать, но сначала придётся разобраться что такое время жизни. Впрочем функциональный подход без garbage collection реализовать непросто, отсюда и сложности в примере топикстартера.

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

В хаскель же лайфтаймы не впилены, хотя было бы реально интересно на это посмотреть.

nezamudich ★★
()

кложура в примере создается в теле функции, а значит при попытке вернуть ссылку без передачи владения, как предлагал tailgunner, мы неизбежно получим «borrowed value does not live long enough».

А значит, нам в любом случае нужно возвращать ссылку с передачей владения, то есть Box. Рабочий пример: https://is.gd/oL8gGR

anonymous
()

да, кстати, к вопросу «почему так сложно». Попытавшись закодить такое на плюсах, вы получите те же самые проблемы. Только там компилятор, вместо того чтобы ругаться непонятными словами и отказываться это собирать, тихо устроит вам undefined behavior. Подумайте об этом :)

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

тихо устроит вам undefined behavior.

Чо серьезно?

#include <iostream>
#include <string>

template <typename A, typename Fun>
auto curry( Fun f, A a )
{
    return [f, a]( auto b ) { return f(a, b); };
}

struct point {
    float x;
    float y;
};

point operator + ( const point &a, const point &b )
{
    return point { a.x + b.x, a.y + b.y };
}

std::ostream & operator << ( std::ostream &o, const point &p )
{
    o << "point { x: " << p.x << ", y: " << p.y << "}";
    return o;
}

int main(int argc, char *argv[])
{
    auto f = curry( [ ](auto x, auto y) { return x + y; }, 20 );
    auto s = curry( [ ](auto x, auto y) { return x + y; }, "Hello " );
    auto p = curry( [ ](auto x, auto y) { return x + y; }, point{ 1.0, 2.0 } );

    std::cout << f(1) << std::endl;
    std::cout << f(10.1) << std::endl;
    std::cout << f(100.1f) << std::endl;
    std::cout << s(std::string("world!")) << std::endl;
    std::cout << p(point{ 4.0, 5.5 }) << std::endl;
}
21
30.1
120.1
Hello world!
point { x: 5, y: 7.5}

где тут UB?

anonymous
()
Ответ на: комментарий от tailgunner
template <typename T>
auto get_curry( T t )
{
    return curry( [ ](auto x, auto y) { return x + y; }, t );
}

int main(int argc, char *argv[])
{
    auto t = get_curry( 100 );
    auto p = get_curry( point {1.0, 1.0} );

    std::cout << t(100) << std::endl;
    std::cout << p(point { 0.0, 0.0 }) << std::endl;

    return 0;
}

так чтоль? И тут где UB?

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

так чтоль?

Примерно так, да.

И тут где UB?

Тут - нет, потому что ты предусмотрительно не передаешь туда указатели. Передай туда указатель и получи UB.

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

А можно пример пользы такого кода на плюсах?

А почему на расте такой код более полезен, чем на плюсах?

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

А давно auto в параметрах лямбды разрешили?

С С++14.

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