How can we ensure that the combination of functions `(x) => Context(y)` and `(y) => Context(z)` is correct in Dart during the syntax analysis phase?

huangapple go评论58阅读模式
英文:

How can we ensure that the combination of functions `(x) => Context(y)` and `(y) => Context(z)` is correct in Dart during the syntax analysis phase?

问题

如何确保在Dart的语法分析阶段,函数组合(x) => Context(y)(y) => Context(z)的组合是正确的?

我正在尝试开发允许组合返回包装在上下文中的值的单子函数的代码。我已经成功创建了一个表现令人满意的函数:

O2 Function(T1)
  combine<T1, T2, T3, O1 extends MetaState<T2>, O2 extends MetaState<T3>>(
      O1 Function(T1) f1, O2 Function(T2) f2) {
  extractor(x) => x.extract();
  return (T1 x) => f2(extractor(f1(x)));
}

但为此,我需要编写类似以下的代码:

var p = combine(
        (int x) => Value<int>(x + 5), 
        (int x) => Value<String>('$x'));

var p2 = combine(p, (int x) => Value<String>('$x')); // IDE中出现错误

而目标是以下语法:

var p = ImmutablePipeline()
      .bind((int x) => Value<int>(x + 5))
      .bind((int x) => Value<String>('$x'))
      .bind((int x) => Value<String>('$x')); // 但在IDE中没有错误

这里是一个执行任务的简单类的示例,但在语法分析阶段不执行正确性检查:

class ImmutablePipeline<T extends MetaState> {
  final Function? pipeline;

  const ImmutablePipeline({Function? initial}) : pipeline = initial;

  T2 extractor<T2>(MetaState<T2> x) => x.extract();

  ImmutablePipeline<T> bind<S>(T Function(S) f) {
    if (pipeline == null) {
      return ImmutablePipeline<T>(initial: f);
    } else {
      T newf(x) => f(extractor(pipeline!(x)));
      return ImmutablePipeline<T>(initial: newf);
    }
  }

  MetaState produce(T s) {
    return pipeline!(s.extract());
  }
}

我尝试了许多变化,但没有达到期望的结果。在这种情况下,Dart中的泛型似乎对我来说非常复杂和不容易理解。重要的是,类的使用不会过于复杂,函数组合在不同上下文中是通用的。也许有人知道更好的解决方法?或者有解决方案吗?有任何想法吗?

英文:

How can we ensure that the combination of functions (x) =&gt; Context(y) and (y) =&gt; Context(z) is correct in Dart during the syntax analysis phase?

I'm attempting to develop code that allows the combination of monadic functions, which return values wrapped in a context. I have managed to create a function that exhibits satisfactory behavior:

O2 Function(T1)
      combine&lt;T1, T2, T3, O1 extends MetaState&lt;T2&gt;, O2 extends MetaState&lt;T3&gt;&gt;(
          O1 Function(T1) f1, O2 Function(T2) f2) {
    extractor(x) =&gt; x.extract();
    return (T1 x) =&gt; f2(extractor(f1(x)));

But for this I need to write something like this:

var p = combine(
        (int x) =&gt; Value&lt;int&gt;(x + 5), 
        (int x) =&gt; Value&lt;String&gt;(&#39;$x&#39;));

var p2 = combine(p, (int x) =&gt; Value&lt;String&gt;(&#39;$x&#39;)); // error in the IDE

And the goal is in the following syntax:

var p = ImmutablePipeline()
      .bind((int x) =&gt; Value&lt;int&gt;(x + 5))
      .bind((int x) =&gt; Value&lt;String&gt;(&#39;$x&#39;))
      .bind((int x) =&gt; Value&lt;String&gt;(&#39;$x&#39;)); // but not error in the IDE

And here's an example of a simple class that performs the task but does not perform the correctness checking during the syntax analysis phase:

class ImmutablePipeline&lt;T extends MetaState&gt; {
  final Function? pipeline;

  const ImmutablePipeline({Function? initial}) : pipeline = initial;

  T2 extractor&lt;T2&gt;(MetaState&lt;T2&gt; x) =&gt; x.extract();

  ImmutablePipeline&lt;T&gt; bind&lt;S&gt;(T Function(S) f) {
    if (pipeline == null) {
      return ImmutablePipeline&lt;T&gt;(initial: f);
    } else {
      T newf(x) =&gt; f(extractor(pipeline!(x)));
      return ImmutablePipeline&lt;T&gt;(initial: newf);
    }
  }

  MetaState produce(T s) {
    return pipeline!(s.extract());
  }
}

I have tried many variations, but I have not achieved the desired result. Generics in Dart seemed very complex and non-trivial to me in this case. It is also important that the usage of the class is not overly complicated and that the function composition is generic across different contexts. Perhaps someone knows a better way to solve this problem? Or a solution? Any ideas?

答案1

得分: 0

你应该看看 https://pub.dev/packages/fpdart 是如何做的。通过引入HKTs形式的元泛型引入了非常巧妙的技巧。

为什么要重新发明fpdart?为什么不在那里贡献?

英文:

You should see how https://pub.dev/packages/fpdart does it. Very clever tricks by introducing meta-generics in the form of HKTs.

And just why are you reinventing fpdart? Why don't you contribute there?

答案2

得分: 0

我不太确定你使用的所有类都在做什么。

如果你想要抽象出单子本身("generic over different contexts" 表示如此),你可能无法实现。这需要高阶泛型,Dart 不支持。
如果你只是想要有相同单子的不同实例化,应该是可行的。

简单地进行单子组合是 "容易的":

MetaState<T3> Function(T1) combine<T1, T2, T3>(
  MetaState<T3> Function(T2) second, MetaState<T2> Function(T1) first) => 
     (T1 v1) => second(first(v1).extract());

这有效,类似以下方式也有效:

abstract class EmptyPipeline<S> {
  ImmutablePipeline<S, T> bind<T>(MetaState<T> Function(S) initial) =>
     ImmutablePipeline<S, T>(initial);
  MetaState<Never> produce(S s) => throw StateError("Empty pipeline");
}

class ImmutablePipeline<S, T> {
  final MetaState<T> Function(S) pipeline;

  const ImmutablePipeline(this.pipeline);

  ImmutablePipeline<S, R> bind<R>(MetaState<R> Function(T) f) =>
     ImmutablePipeline<S, R>((S s) => f(pipeline(s).extract()));

  MetaState<T> produce(MetaState<S> s) => pipeline(s.extract());
}

如果这是你想要它做的事情。

英文:

I'm not entirely sure what all the classes you use are doing.

If you want to abstract over the monad itself ("generic over different contexts" suggests so), you likely cannot. That would require higher-order generics, which Dart doesn't have.
If you just want to have different instantiations of the same monad, it should be doable.

Simply doing a monadic combine is "easy":

MetaState&lt;T3&gt; Function(T1) combine&lt;T1, T2, T3&gt;(
  MetaState&lt;T3&gt; Function(T2) second, Metastate&lt;T2&gt; Function(T1) first) =&gt; 
     (T1 v1) =&gt; second(first(v1).extract());

That works, and so does something like:

abstract class EmptyPipeline&lt;S&gt; {
  ImmutablePipeline&lt;S, T&gt; bind&lt;T&gt;(MetaState&lt;T&gt; Function(S) initial) =&gt;
     ImmutablePipeline&lt;S, T&gt;(initial);
  MetaState&lt;Never&gt; produce(S s) =&gt; throw StateError(&quot;Empty pipeline&quot;);
}

class ImmutablePipeline&lt;S, T&gt; {
  final MetaState&lt;T&gt; Function(S) pipeline;

  const ImmutablePipeline(this.pipeline);

  ImmutablePipeline&lt;S, R&gt; bind&lt;R&gt;(MetaState&lt;R&gt; Function(T) f) =&gt;
     ImmutablePipeline&lt;S, R&gt;((S s) =&gt; f(pipeline(s).extract()));

  MetaState&lt;T&gt; produce(MetaState&lt;S&gt; s) =&gt; pipeline(s.extract());
}

if that is what you want it to do.

huangapple
  • 本文由 发表于 2023年5月30日 03:17:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76359867.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定