ML仿函数可以用.NET接口和泛型实际表达吗?是否有一个先进的ML仿函数使用示例来抵制这种编码?
回答摘要:
在一般情况下,答案是否定的。 ML模块提供不直接映射到.NET概念的功能(例如通过签名共享规范[1])。
但是,对于某些用例,可以翻译ML习语。这些案例不仅包括基本Set
仿函数[2],还包括monads [3]的函数编码,以及Haskell的更高级用法,例如最终无标记解释器[ 4,5]。
实用编码需要妥协,例如半安全的低压。你的里程会很谨慎。
博客和代码:
答案 0 :(得分:11)
HigherLogics是我的博客,我花了很多时间来研究这个问题。这种限制确实是对类型构造函数的抽象,即“泛型泛型”。似乎你可以做的最好的模仿ML模块和仿函数需要至少一个(半安全)演员。
它基本上归结为定义一个抽象类型,以及一个对应于对该类型进行操作的模块签名的接口。抽象类型和界面共享一个类型参数B,我称之为“品牌”;品牌通常只是实现模块接口的子类型。该品牌确保传入的类型是模块所期望的正确子类型。
// signature
abstract class Exp<T, B> where B : ISymantics<B> { }
interface ISymantics<B> where B : ISymantics<B>
{
Exp<int, B> Int(int i);
Exp<int, B> Add(Exp<int, B> left, Exp<int, B> right);
}
// implementation
sealed class InterpreterExp<T> : Exp<T, Interpreter>
{
internal T value;
}
sealed class Interpreter : ISymantics<Interpreter>
{
Exp<int, Interpreter> Int(int i) { return new InterpreterExp<int> { value = i }; }
Exp<int, Interpreter> Add(Exp<int, Interpreter> left, Exp<int, Interpreter> right)
{
var l = left as InterpreterExp<int>; //semi-safe cast
var r = right as InterpreterExp<int>;//semi-safe cast
return new InterpreterExp<int> { value = l.value + r.value; }; }
}
}
正如您所看到的,演员阵容大多是安全的,因为类型系统确保表达式类型的品牌与解释器的品牌相匹配。解决这个问题的唯一方法是,如果客户创建自己的Exp类并指定Interpreter品牌。有一个更安全的编码可以避免这个问题,但它对于普通的编程来说太笨重了。
我后来used this encoding and translated the examples来自Oleg的MetaOCaml论文之一,使用C#和Linq。解释器可以透明地运行在ASP.NET或客户端使用此嵌入式语言服务器端编写的程序作为JavaScript。
这种对解释器的抽象是Oleg最终无标签编码的一个特征。博客文章中提供了他论文的链接。
接口在.NET中是一流的,由于我们使用接口来编码模块签名,因此模块和模块签名在此编码中也是一流的。因此,仿函数只是直接使用接口代替模块签名,即。他们会接受ISymantics&lt; B&gt;的实例。并委托任何电话。
答案 1 :(得分:8)
我不太清楚ML仿函数能够真正回答你的问题。但我要说的是,我总是在 monadic 编程中找到的.Net的一个限制因素是,无法在“forall M. 某种类型表达式的意义上对'M'进行抽象,其中M&lt; T&gt; “(例如,其中M是类型构造函数(带有一个或多个泛型参数的类型))。因此,如果你有时需要/使用仿函数,那么我非常有信心在.Net上表达它没有好办法。
答案 2 :(得分:6)
ML模块的一个关键特性是共享规范。 .NET中没有能够模仿它们的机制 - 所需的机制就太不同了。
您可以尝试通过将共享类型转换为参数来实现,但这不能忠实地模拟定义签名的能力,然后可能以多种不同的方式应用共享。
在我看来,.NET将从拥有这种机制的东西中受益 - 它将更接近真正支持现代语言的多样性。希望包括模块系统的最新进展,如MixML中的模块系统,我认为模块系统的未来。 http://www.mpi-sws.org/~rossberg/mixml/
答案 3 :(得分:3)
我现在已将a detailed description的ML模块,签名和仿函数发布到等效的C#编码中。我希望有人觉得它很有用。
答案 4 :(得分:2)
布莱恩的评论很有见。这是OCaml代码,它使用仿函数为相关monad上的Haskell sequence :: (Monad m) => [m a] -> m [a]
的(严格)实现提供参数:
module type Monad =
sig
type 'a t (*'*)
val map : ('a -> 'b) -> ('a t -> 'b t)
val return : 'a -> 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
end
module type MonadUtils =
sig
type 'a t (*'*)
val sequence : ('a t) list -> ('a list) t
end
module MakeMonad (M : Monad) : MonadUtils =
struct
type 'a t = 'a M.t
let rec sequence = function
| [] ->
M.return []
| x :: xs ->
let f x =
M.map (fun xs -> x :: xs) (sequence xs)
in
M.bind x f
end
这在.NET中表达起来很有挑战性。
<强>更新强>:
使用naasking
的技术我能够以大多数类型安全的方式对F#中的可重用sequence
函数进行编码(使用向下转换)。