Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lambdas for nix #189

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Add lambdas for nix #189

wants to merge 1 commit into from

Conversation

valodzka
Copy link

Implementent lambdas for nix. Interpolation - Multiple Calls skipped because nix is pure functional language so lambda cannot have state / return different result.

Copy link
Member

@jgonggrijp jgonggrijp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look fine to me, but are you sure there is no way to implement Interpolation - Multiple Calls? Is there nothing like Haskell's State monad? How does nix implement pseudorandom number generators?

@valodzka
Copy link
Author

How does nix implement pseudorandom number generators?

From what I found used approach is to generate sequence.

but are you sure there is no way to implement Interpolation - Multiple Calls?

I'm not nix expert so I asked for help, may be someone more knowledgeable than me know the solution.

@valodzka
Copy link
Author

@jgonggrijp Based on the response to my post on the Nix Discourse forum and also on this similar question

would require something akin to a monadic context
But that’s not a thing.

It seems that implementing something similar to a monadic context would be necessary. However, such a concept doesn't currently exist in Nix.

@jgonggrijp
Copy link
Member

@valodzka Thanks for sharing those links. The next reply to that similar question (comment by AndersonTorres) lists several links with instructions on how you can implement monads yourself. I visited the first one, which illustrated the concept for Scheme. Looking at the Scheme code, I see nothing that is specific to Scheme or that requires variable modifications or other special facilities. I think you could also implement them in C or Nix.

Concluding, I still think it should be possible to implement Interpolation - Multiple Calls in Nix. Please let me know whether you want to have a go at it, otherwise I will just merge it as-is.

@jgonggrijp
Copy link
Member

By the way, Wikipedia also has code examples:

https://en.wikipedia.org/wiki/Monad_(functional_programming)

@valodzka
Copy link
Author

@jgonggrijp after more discussion it looks like it can be implemented but only with a kind of breaking interface. It would require that:

  1. library user provide lambda that returns special structure, not plain string / primitive
  2. library handle such structures in special way (use result for rendering, not returned value itself and pass returned value to parameter to lamda call)

So lamda will look like this:

s: 
  let 
     state = if s == null then { result = 0; nextState = 1; } else s; 
  in 
    { result = state.nextState; newState = state.nextState + 1; }

I am not sure if this is worth it, but if you think it's necessary I can update the pull request.

@jgonggrijp
Copy link
Member

@valodzka That comment by rhendric is gold, please pass them my appreciation.

You are right that any stateful lambda will necessarily require interface changes in your Mustache implementation, if your implementation is to pass that test. It is entirely up to you whether you want to invest that effort.

That being said, you can write some monadic form of the lambda for this test, without making any changes anywhere else. This will not break the spec itself, and the only consequence for your implementation is that it will fail this particular test. Which is exactly as it should be; the spec expects implementations to support stateful lambdas, and yours does not (at least not yet).

In other words, please write a monadic form, but do not feel obliged to pass it. I recommend a lambda form that assumes a more generic state monad, so that you can easily add support for other types of stateful behavior later. Something like this:

v: state @ { count ? 1 }:
    let
        next = count + 1;
    in
        { result = count; state = state // { count = next } };

If you later decide to actually support stateful lambdas, the part of your implementation that interpolates them can detect whether a lambda returned a bare value or a monad, and wrap it in a monad with unit/return in the first case. In this way, you and your users won't need to rewrite stateless lambdas. The corresponding unit/return and bind/>>= implementations would look something like this:

unit = value: state: { result = value; state = state };
bind = previous: func: state:
    let
        intermediate = previous state;
    in
        func intermediate.result intermediate.state;

@RaitoBezarius
Copy link

I didn't understand you wanted to do Mustache stuff in Nix.

Here's a lead on how to perform "monadic-style" stuff in Nix, though I highly don't recommend relying on this, this is not supposed to be public interface and may be removed in a future version of Nix:

let next = rec { state = 0; __functor = old: _: old // { state = old.state + 1; }; }; in next {} {} {} {} {}   

__functor enable an attribute set to act as a function.

@jgonggrijp
Copy link
Member

@RaitoBezarius Thanks for chiming in. Assuming that __functor disappears, would you recommend something more like what I suggested, or would you still recommend a different approach?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants