none
Convert text to function type RRS feed

  • Question

  • The context for this is as follows:

    I would like to pull functions saved as text from a URI and invoke them.

    Mechanically, per the library specification I cannot see why I cannot take a known valid function, wrap it in quotes to make it text, then cast the text as a function using the 'as function' construct.

            

    [

    let
        Source = Text.FromBinary(Web.Contents("www.com")),
        Eval = Function.Invoke((Source), {#date(2012,1,1), #date(2013,1,1)}), //FAIL

        A = "(x as number) => (1 + x)",  
        AA = ((x as number)=> 1+x) as function, //SUCCESS
        InvokedAA = AA(6), //SUCCESS

        fy=(y)=> 1+y,  //SUCCESS  

        AEval = Function.Invoke(A,{4}),  //FAIL
        InvokedAA = A(5),  //FAIL

        B = Function.Invoke(InvokedAA,{4}),  //SUCCESS
        Y = fy(4),  //SUCCESS
        AAA = Function.Invoke("(x)=>1+x",{4}),  //FAIL
        AYY = Function.Invoke((x)=>1+x,{4}),   //SUCCESS


        AAY = ((x as number)=> 1+x) as function,  //FAIL
        Fail = A as function  //SUCCESS

    in
        Fail

    ]

    Thank you very much for your attention

    Tuesday, March 4, 2014 4:54 PM

Answers

  • I obviously can't dispute the fact that this is potentially useful. The down side is about the possible impact this will have on our ability to evolve the product in the future while ensuring that we retain backwards compatibility with previous versions of the product.
    Thursday, March 13, 2014 3:12 PM

All replies

  • You need to evaluate the text in order to turn it into a function:

    let
        Source = "(value) => Text.From(value)",
        Function = Expression.Evaluate(Source, [#"Text.From" = Text.From]),
        Invoked = Function(2)
    in
        Invoked

    The ability to pass "#shared" as the environment to Expression.Evaluate is probably a bug, whereas if you know specifically which functions you expect to use and can build an environment from them, then your code will be much more future-proof.

    Tuesday, March 4, 2014 5:21 PM
  • Excellent!

    I am not sure what the bracketed portion is doing - I suspect forcing the compiler to understand that Text.From is a function and not text.  

    The following lines I inserted into my query and got the desired result:

    Evalu = Expression.Evaluate(A) as function,
        InvokedEvalu = Evalu(5), // Result of formula 1 + 5 = 6


    Thank you very much!

    Tuesday, March 4, 2014 5:29 PM
  • The second parameter to Expression.Evaluate is a record which defines a set of functions to expose to the evaluated expression. If you say

    Expression.Evaluate("f()")

    then you'll get an error because "f" isn't defined -- and this is true even if you replace "f" with something like "DateTime.LocalNow" that is part of the standard library. In order to use external functions from inside the context of Expression.Evaluate, you need to pass them in as part of the environment:

    Expression.Evaluate("f()", [f = () => "Hello world"])

    What some people have discovered is that you can currently pass "#shared" as the environment argument and basically inherit the entire standard library without having to pass in the individual functions being used. Some of the people on the product team think this is a bug, because we disallow the use of #shared in certain other circumstances. I don't think we have a final decision on that, though.

    Tuesday, March 4, 2014 5:40 PM
  • Yeah, it is pretty great that I can write a function and pass #shared so that I can write my aggregate function using standard functions in the base library and then not have to declare that I am using those functions from the base library.

    My alternative would be potentially having to declare a huge list of functions.

    What is the downside of allowing users this convenience?  Beyond that why not default the environment to #shared?

    Tuesday, March 4, 2014 5:48 PM
  • I obviously can't dispute the fact that this is potentially useful. The down side is about the possible impact this will have on our ability to evolve the product in the future while ensuring that we retain backwards compatibility with previous versions of the product.
    Thursday, March 13, 2014 3:12 PM
  • Thank you for the response, I appreciate the issues you have brought up.  

    Here is an issue that I am running into.  I have certain queries and functions that I would like to modularize make available over a network via an index.  I would like to be able to import modules by calling upon their text through this index.   

    As things stand, if the #shared environment 'bug' is not available, then determining the standard library functions that I need to bring into the evaluated environment becomes a cumbersome process.  I would almost need a new function to walk through the library and look for those function calls one by one.

    Is there an easier way to call the standard functions without using the #shared bug?

    Wednesday, April 23, 2014 6:53 PM