Craig
Craig

Reputation: 1940

How to convert a seemingly self-calling F# lambda to C#?

I'm trying to convert some F# code to C# but I don't understand this particular block:

let GetItems = asyncResult {
    let! items = StaticClass.getItems
    return 
        items
        |> AsyncSeq.map (fun item -> 
            fun handleItem -> asyncResult {
                let! itemCanBeRemoved = handleItem item|> AsyncResult.mapError HandleItemError
                // some code removed for clarity
            })
 }

My attempt to convert this is:

public static async Task<IEnumerable<T>> GetItems<T>() where T : Item
{
    var items = await StaticClass.GetItems();

    var tasks = new List<Task>();
    foreach (var item in items)
    {
        bool itemCanBeRemoved;
        if (itemCanBeRemoved)
        {
            // do something
        }
        else
        {
            // do something else
        }
    }

    await Task.WhenAll(tasks);

    return items;
}

Assuming my conversion is on the right track, I don't understand how the handleItem func is defined and then invoked within its own implementation block. Can someone please explian what handleItem is doing and how it invokes itself?

Upvotes: 0

Views: 170

Answers (2)

Tomas Petricek
Tomas Petricek

Reputation: 243051

The key part of your code sample does not actually define a self-calling (i.e. recursive) lambda.

items 
|> AsyncSeq.map (fun item -> 
    fun handleItem -> asyncResult {
        let! itemCanBeRemoved = handleItem item|> AsyncResult.mapError HandleItemError
        // some code removed for clarity
    })

What this does is that it iterates over all items and generates a new AsyncSeq<T> where each item is generated from the original one by calling:

fun handleItem -> asyncResult {
    let! itemCanBeRemoved = handleItem item|> AsyncResult.mapError HandleItemError
    // some code removed for clarity
}

This is not recursive - it defines a lambda that takes handleItem (presumably a function that can be used to handle the individual items) and returns asyncResult.

If I understand the code correctly, it would then return something like:

AsyncSeq<(Item -> AsyncResult<Result, Err>) -> AsyncResult<Result, Err>>

This would be an asynchronously generated collection of functions that take function (to process each item) and return result of this processing.

This looks like a very odd thing to do, so I guess this is either badly copied from your actual source code, or it is just very bad F# code.

That said, neither AsyncResult nor AsyncSeq have a direct corresponding type in C#, so translating this might be quite hard.

Upvotes: 1

Aaron M. Eshbach
Aaron M. Eshbach

Reputation: 6510

It's hard to tell exactly what the original code is doing without a complete sample, but if I had to guess, I'd say the F# code is likely using a fixed-point combinator to process the items in the list. This can be accomplished in C# by using null-initialized Func definition to support a recursive-lambda in a LINQ statement.

Func<Item, ValueTuple<Item, bool>> handleItem = null;
handleItem = item => {
    var itemCanBeRemoved = handleItem item; // Should do something so that it's not infinitely recursive here
    return (item, itemCanBeRemoved);

};

return items.Select(handleItem);

You can reference a similar question here for a more detailed explanation: https://stackoverflow.com/a/61206/1748071

Upvotes: 2

Related Questions