Skip to content

yieldRepeatIO creates memory leak when not using IO #1497

@cheerio-pixel

Description

@cheerio-pixel

As the title says. Here is a code that exemplifies this problem:

global using static AppPrelude;
using LanguageExt.Pipes;
using LanguageExt;
using static LanguageExt.Prelude;
using LanguageExt.Traits;
using System.Runtime.CompilerServices;
using System.Net.Sockets;
using System.Net;
using System.Text;
using LanguageExt.Common;
using LanguageExt.Sys;
using M = Application;

var effect = Module<M>.producer | Module<M>.pipe | Module<M>.consumer;
// effect.Run().As().Run();
effect.Run().As().Run.Run(new (AtomHashMap(("", "")))).Run().Ignore();

public static class AppPrelude
{

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Application<A> As<A>(this K<Application, A> self) =>
        (Application<A>)self;
}

public record ApplicationState(AtomHashMap<string, string> Cache);

public record Application<A>(StateT<ApplicationState, IO, A> Run) : K<Application, A>;

public class Application
: Deriving.Monad<Application, StateT<ApplicationState, IO>>,
  Deriving.Stateful<Application, StateT<ApplicationState, IO>, ApplicationState>,
  MonadIO<Application>
{
    public static K<Application, A> LiftIO<A>(IO<A> ma)
    {
        return new Application<A>(
                StateT.liftIO<ApplicationState, IO, A>(ma)
                );
    }

    public static K<StateT<ApplicationState, IO>, A> Transform<A>(K<Application, A> fa)
    {
        return fa.As().Run;
    }

    public static K<Application, A> CoTransform<A>(K<StateT<ApplicationState, IO>, A> fa)
    {
        return new Application<A>(fa.As());
    }
}

public static class Module<M>
where M : MonadIO<M>
{
    public static ProducerT<int, M, Unit> producer =>
        from _2 in IO.lift(() => Console.WriteLine("Producer"))
        from _1 in ProducerT.yieldRepeatIO<M, int>(
                IO.pure(1)
                    )
        select unit;

    public static PipeT<int, int, M, Unit> pipe =
        from i in PipeT.awaiting<M, int, int>()
        from _2 in IO.lift(() => Console.WriteLine("Pipe"))
        from _ in PipeT.yieldRepeatIO<M, int, int>(IO.pure(i))
        select unit;

    public static ConsumerT<int, M, Unit> consumer =
        from x in ConsumerT.awaiting<M, int>()
        from _2 in IO.lift(() => Console.WriteLine("Consumer"))
        select unit;
}

This is in the latest version (language v5-beta54)
The commented run is for IO, which if you substitue for M is going to work as expected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions