导致错误“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
}
我认为你对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 类型的TState
和TResult
参数的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; }
}