【发布时间】:2016-02-19 22:00:22
【问题描述】:
我已经实现了一个 State monad,并且正在努力使用扩展方法启用 LINQ“理解语法”。
谁能提供有关标题错误原因的见解?可能缺少扩展方法,或者签名错误。令人费解的是,LINQ 更详细的方面可以工作,而像 let 子句这样看似微不足道的事情却没有。
请注意:其他地方有很多关于“select”或“join”子句的类似错误的帖子;我无法辨别出与下面的案例有任何相似之处。
这个例子可以正确编译和运行:
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);
} );
}
}
以下是 State monad 类的基本要素:
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
}
【问题讨论】:
-
@Codexer 不这么认为;我现在在我的代码中有一个示例,当我用静态函数替换 lambda 时仍然无法编译。同样,当我将 lambda 中的用法作为对
s的字段引用时。 -
这一切都令人难以置信,但如果我可以编译它,我或许可以提供一些见解。我在任何地方都找不到 StateTuple 的声明。在构建之前继续添加声明是否安全?
-
State<T, S>.Get的定义在哪里?缺少很多定义来编译它。 -
@recursive:添加了
StructTuple代码。我还没有把它削减到最低限度。我相信可以添加我无意中遗漏的任何东西的假人。 -
@PieterGeerkens:感谢更新,虽然新增的内容有自己的编译问题,比如
StateTuple引用了一些未声明的泛型参数。我将做出一些有根据的假设。
标签: c# linq extension-methods monads