Posted: Mar 08, 2012 8:26 pm
by mizvekov
VazScep wrote:Oohh...this is new.

So here's the question: suppose b is a pointer to a dynamically allocated object, and this code appears in a function where the lambda foo is returned. How does the memory management work out? Are there useful smart pointers to deal with it?

Yes, there are a few additions to the standard, that came from boost, that will help here.
You can start by using std::shared_ptr, which is a reference counted pointer container, that will delete automatically when the count reaches 0.
Code: Select all
struct B {
        int val;
        B(int v) : val(v) {}
        ~B() { std::cout << "bye " << val << std::endl; }

std::function<int(int)> f(std::shared_ptr<B> b) {
        return [b](int a) -> int { return a + b->val; };

std::function<int(int)> g() {
        auto a = std::make_shared<B>(10), b = std::make_shared<B>(20);
        return f(a);
int main() {
                auto foo = g();
                auto bar = std::bind(foo, 1);
                std::cout << foo(2) << ' ' << bar() << std::endl;
        std::cout << "the end" << std::endl;

This will print
Code: Select all
bye 20
12 11
bye 10
the end

I am also using std::function there too, which is a polymorphic wrapper for any callable type.

I think the latter chapters in "School of Expression" are worth a read, especially the stuff on reactive programming. Other than that, there's Haskellwiki, which has articles on more advanced stuff like monad transformers and arrows. After that, I guess it's just research papers. When I was getting interested in Software Transactional Memory back in 2006, I was having to read Peyton-Jones' (very nicely-written) research papers.

I see, thanks!

Does it not have variable assignment and update and globals?

At least they never introduced it to us, so like I said, it was a pretty limiting experience. It was like programming with both hands tied. I would be given a problem, then solve it almost instantly in my head, but then take a long time translating that into a pretty constrained language.

I've never used Scheme. Common Lisp on the other hand allows for the nastiest side-effects you can imagine. The components of any cons-cell can be mutated, so you can be handed a list, make a destructive modification on it, and find that you've radically altered data structures all over the place which happened to share parts of the original list. And this is before we getting into rebinding function symbols on the fly or making changes to the dispatch mechanism of functions. :ill:

Wow, I misjudged the LISP guys, I thought they would find something like that an aberration and kill it with fire.

Though I'm a little sceptical about using monads or any combinator language in an untyped language. The first serious combinator languages that I'm aware of came from ML, and one of the main guys in the ML community back then stressed that "tactic" combinators were only possible when you had a type system for higher-order functions. Often, when I'm working with monads and monad transformers, I'm not really thinking about code or thinking about what a function does. It's too abstract for me by that point. I get by just thinking entirely at the level of types. And I really don't want my frequent mistakes to show up as runtime exceptions. Given the heavy dosage of lambdas involved, I expect most of those exceptions to be thrown from closures a good distance away from the original error.

I see, your work is pretty interesting :)