导致错误“let 子句中的表达式类型不正确”的原因

本文关键字:类型 表达式 不正确 错误 let 子句 | 更新日期: 2023-09-27 18:35:34

我已经实现了一个状态monad,并且正在努力使用扩展方法启用LINQ"理解语法"。

任何人都可以提供有关标题错误原因的见解吗?也许缺少扩展方法,或者签名错误。令人费解的是,LINQ 的更详细的方面工作,以及看似像 let 子句一样微不足道的东西,却不是。

请注意:其他地方有许多关于"选择"或"加入"条款的类似发音错误的帖子;我无法辨别与下面我的情况有任何相似之处。

此示例正确编译并运行:

namespace StateMonad {
  using StateUnit = State<Unit,GCDState>;
  using TupleUnit = State<Unit,GCDState>.StateTuple;
  private static class TestClass  {
    // This usage compiles and runs fine.
    private static readonly StateUnit GcdInner_Good =
      ( from s in State<Unit,GCDState>.Get
        select new TupleUnit(Unit.unit, 
              s.A > s.B ? new GCDState(s.B, s.A-s.B)
            : s.A < s.B ? new GCDState(s.B,   s.A  )
                        : s)
      );
// continued below

但是这个没有,在第一个let上产生感兴趣的错误:

// continued from above  
    // This usage fails to compile, with error as shown
    private static readonly StateUnit GcdInner_Bad =
      ( from s in State<Unit,GCDState>.Get
        let A = s.A       // Generates error on "let":
        let B = s.B       //   "The type of the expression in the let clause is incorrect.
                          //    Type inference failed in the call to 'Select'."
        select new TupleUnit(Unit.unit, 
              A > B ? new GCDState(B, A - B)
            : A < B ? new GCDState(B,   A  )
                        : s)
      );
  }
}

以下是到目前为止声明的扩展方法:

  public static class StateExtensions {
    [Pure]public static State<TResult,TState>    Select<TValue,TState,TResult>( this
      State<TValue,TState> @this,
      Func<TValue,State<TResult,TState>.StateTuple> projector
    ) where TResult:struct where TState:struct where TValue:struct {
      projector.ContractedNotNull("projector");
      return new State<TResult,TState>(s => projector(@this.EvalState(s)));
    }
    [Pure]public static State<TResult,TState>    SelectMany<TValue,TState,TResult>( this
        State<TValue,TState> @this,
        Func<TValue,State<TResult,TState>> selector
    ) where TResult:struct where TState:struct where TValue:struct {
        selector.ContractedNotNull("selector");
        return @this.Bind(selector);
    }
    [Pure]public static State<TResult,TState>   SelectMany<TValue,TState,T,TResult>( this
        State<TValue,TState> @this,
        Func<TValue, State<T,TState>> selector,
        Func<TValue, T, TResult> projector
    ) where TResult:struct where TState:struct where TValue:struct where T:struct {
        selector.ContractedNotNull("selector");
        projector.ContractedNotNull("projector");
        return new State<TResult, TState>(s => {
            var value = @this.RunState(s).Value;
            return new State<TResult, TState>.StateTuple(
                projector(value, selector(value).RunState(s).Value) ,s);
        } );    
    }
  }

以下是国家单体类的基本要素:

  public struct State<TValue,TState> : IEquatable<State<TValue,TState>>
  where TValue:struct where TState:struct {
    public delegate StateTuple Transformer(TState state);
    public State(Transformer transformer) : this() {
        Contract.Requires(transformer != null);
        _transformer = transformer;
    }
    [Pure]public State<TResult,TState>    Bind<TResult> (
      Func<TValue, State<TResult,TState>> selector
    ) where TResult:struct {
        selector.ContractedNotNull("selector");
        var @this = this;
        return new State<TResult,TState>(state => {
            var tuple = @this.RunState(state);
            return selector(tuple.Value).RunState(tuple.State);
        } );
    }
    [Pure]public StateTuple   RunState(TState state)  { return _transformer(state); }
    [Pure]public TValue       EvalState(TState state) { return RunState(state).Value; }
    [Pure]public TState       ExecState(TState state) { return RunState(state).State; }
    private readonly Transformer _transformer;
  }

public struct StateTuple {
  public StateTuple(Tuple<TValue, TState> content) : this(content.Item1,content.Item2) {
      content.ContractedNotNull("content");
  }
  public StateTuple(TValue value, TState state ) : this() {
      _value = value; _state = state;
  }
  public TValue Value { get {return _value;} } readonly TValue _value;
  public TState State { get {return _state;} } readonly TState _state;
  #region Value Equality with IEquatable<T>.
  /// <inheritdoc/>
  [Pure]public override bool Equals(object obj) { 
    var other = obj as StateTuple?;
    return other != null  &&  other.Equals(obj);
  }
  /// <summary>Tests value-equality, returning <b>false</b> if either value doesn't exist.</summary>
  [Pure]public bool Equals(StateTuple other) {
    return this.Value.Equals(other.Value)  &&  this.State.Equals(other.State);
  }
  /// <inheritdoc/>
  [Pure]public override int GetHashCode() { unchecked { return Value.GetHashCode() ^ State.GetHashCode(); } }
  /// <inheritdoc/>
  [Pure]public override string ToString() {
    Contract.Ensures(Contract.Result<string>() != null);
    return String.Format("({0},{1})",Value,State);
  }
  /// <summary>Tests value-equality, returning <b>false</b> if either value doesn't exist.</summary>
  [Pure]public static bool operator == (StateTuple lhs, StateTuple rhs) { return lhs.Equals(rhs); }
  /// <summary>Tests value-inequality, returning <b>false</b> if either value doesn't exist..</summary>
  [Pure]public static bool operator != (StateTuple lhs, StateTuple rhs) { return ! lhs.Equals(rhs); }
  #endregion
}

以下是编译所需的更多实用程序:

  /// <summary>TODO</summary>
  public static class State {
    public static State<bool,TState>            DoWhile<TState>( this
        State<bool,TState>.Transformer body
    ) where TState:struct {
        return new State<bool,TState>(state => {
            State<bool,TState>.StateTuple tuple;
            do { tuple = body(state); state = tuple.State; } while (tuple.Value);
            return tuple;
        } );
    }
    /// <summary>Implements the Haskell operator (liftM): liftM f m = m >>= ('x -> return (f x))</summary>
    public static State<B,TState> LiftM<TState,A,B>( this
        State<A,TState> @this,
        Func<A,B> func
    ) where TState:struct where A:struct where B:struct {
        return @this.Bind(t => new State<B,TState>(s => new State<B,TState>.StateTuple(func(t),s)) );
    }
  }
  /// <summary>TODO</summary>
  public static class State<TState> where TState:struct {
    public readonly static State<TState, TState>    Get
        = new State<TState, TState>(s => new State<TState,TState>.StateTuple(s, s));
    public          static State<Unit,TState>       Put(TState state) {
        return new State<Unit,TState>( s => new State<Unit,TState>.StateTuple(Unit.unit,state) );
    }
    #region Convenience extensions to Get() for efficiency
    /// <summary>TODO</summary>
    /// <typeparam name="TValue"></typeparam>
    /// <typeparam name="TState"></typeparam>
    /// <param name="selector"></param>
    [Pure]public static State<TValue,TState>   GetBind<TValue>(
        Func<TState, State<TValue,TState>> selector
    ) where TValue:struct {
        selector.ContractedNotNull("selector");
        return new State<TValue,TState>( s => selector(s).RunState(s) );
    }
    /// <summary>TODO</summary>
    /// <typeparam name="TValue"></typeparam>
    /// <typeparam name="TState"></typeparam>
    /// <param name="selector"></param>
    [Pure]public static State<TValue,TState>   GetCompose<TValue>(
        Func<TState,State<TValue,TState>> selector
    ) where TValue:struct {
        selector.ContractedNotNull("selector");
        return new State<TValue,TState>( s => selector(s).RunState(s) );
    }
    /// <summary>TODO</summary>
    /// <typeparam name="TValue"></typeparam>
    /// <typeparam name="TState"></typeparam>
    /// <param name="selector"></param>
    [Pure]public static State<Unit,TState>    GetComposePut(
        Func<TState,TState> transform
    ) {
        transform.ContractedNotNull("transform");
        return new State<Unit,TState>( s => new State<Unit,TState>.StateTuple(Unit.unit,transform(s)) );
    }
    /// <summary>TODO</summary>
    /// <typeparam name="TValue"></typeparam>
    /// <typeparam name="TState"></typeparam>
    /// <param name="selector"></param>
    [Pure]public static State<TValue,TState>   GetSelect<TValue>(
        State<TValue,TState>.Transformer projector
    ) where TValue:struct {
        projector.ContractedNotNull("projector");
        return new State<TValue,TState>(projector);
    }
    #endregion
  }

导致错误“let 子句中的表达式类型不正确”的原因

我认为你对Select的定义是问题所在。它应该具有类型 State<T, S> -> Func<T, R> -> State<R, S>即它应该只对结果类型进行操作,而不是对状态进行操作。如果添加具有该签名的实例方法:

public State<TResult, TState> Select<TResult>(Func<TValue, TResult> selector)
{
    Transformer t = this._transformer;
    var inner = new State<TResult, TState>.Transformer(s =>
    {
        var inter = t(s);
        return new State<TResult, TState>.StateTuple(selector(inter.Value), inter.State);
    });
    return new State<TResult, TState>(inner);
}

请注意,上面的定义需要 State 类型的TStateTResult参数的struct限制(这不应该是必需的)。

然后修复状态表达式的类型:

private static readonly State<TupleUnit, GCDState> GcdInner_Good =
      (from s in State<Unit, GCDState>.Get
       select new TupleUnit(Unit.unit,
             s.A > s.B ? new GCDState(s.B, s.A - s.B)
           : s.A < s.B ? new GCDState(s.B, s.A)
                       : s)
      );
        private static readonly State<TupleUnit, GCDState> GcdInner_Bad =
      (from s in State<Unit, GCDState>.Get
       let A = s.A
       let B = s.B
       select new TupleUnit(Unit.unit,
             A > B ? new GCDState(B, A - B)
           : A < B ? new GCDState(B, A)
                       : s)
      );

然后他们都会输入检查。

包含let子句的查询表达式,如下所示

from s in src
let x = s.Expr
select x

将转换为:

src.Select(s => new { S = S, X = s.Expr }).Select(s => s.X);

并且编译器无法推断中间Select调用的类型。这可能是因为它是一个扩展方法,并且包含一个未使用的类型参数。如果将其设置为实例方法,则可以消除这种歧义。

以下 State 实现支持在查询语法中使用 let

public class State<TState, TResult>
{
    private readonly Func<TState, StateResult<TState, TResult>> f;
    public State(Func<TState, StateResult<TState, TResult>> f)
    {
        this.f = f;
    }
    public StateResult<TState, TResult> Run(TState state)
    {
        return this.f(state);
    }
    public TResult RunResult(TState state)
    {
        return this.f(state).Result;
    }
    public TState RunState(TState state)
    {
        return this.f(state).State;
    }
    public State<TState, TOut> Select<TOut>(Func<TResult, TOut> mapFunc)
    {
        Contract.Requires(mapFunc != null);
        return new State<TState, TOut>(s =>
        {
            var thisResult = this.f(s);
            return new StateResult<TState, TOut>(s, mapFunc(thisResult.Result));
        });
    }
    public State<TState, TOut> BiSelect<TOut>(Func<StateResult<TState, TResult>, StateResult<TState, TOut>> mapFunc)
    {
        return new State<TState, TOut>(s =>
        {
            return mapFunc(this.f(s));
        });
    }
    public State<TState, TOut> SelectMany<TOut>(Func<TResult, State<TState, TOut>> bindFunc)
    {
        return SelectMany(bindFunc, (_, r) => r);
    }
    public State<TState, TOut> SelectMany<TInter, TOut>(Func<TResult, State<TState, TInter>> bindFunc, Func<TResult, TInter, TOut> selector)
    {
        return new State<TState, TOut>(initialState =>
        {
            var thisResult = this.f(initialState);
            var nextState = bindFunc(thisResult.Result);
            var nextResult = nextState.Run(thisResult.State);
            var result = selector(thisResult.Result, nextResult.Result);
            return new StateResult<TState, TOut>(nextResult.State, result);
        });
    }
}
public static class State
{
    public static State<TState, TResult> FromResult<TState, TResult>(TResult result)
    {
        return new State<TState, TResult>(s => new StateResult<TState, TResult>(s, result));
    }
    public static State<TState, TState> Get<TState>()
    {
        return new State<TState, TState>(s => new StateResult<TState, TState>(s, s));
    }
    public static State<TState, Unit> Put<TState>(TState state)
    {
        return new State<TState, Unit>(_ => new StateResult<TState, Unit>(state, Unit.Instance));
    }
    public static State<TState, Unit> Modify<TState>(Func<TState, TState> modifyFunc)
    {
        return from s in Get<TState>()
               from _ in Put(modifyFunc(s))
               select Unit.Instance;
    }
}
public struct StateResult<TState, TResult>
{
    public StateResult(TState state, TResult result)
        : this()
    {
        this.State = state;
        this.Result = result;
    }
    public TState State { get; private set; }
    public TResult Result { get; private set; }
}