Pode ML ficheiro ser totalmente codificado em .NET (C#/F#)?
Pergunta
Pode ML ficheiro ser expressa de maneira prática com .NET interfaces e os genéricos?Há uma avançada ML functor usar o exemplo que desafia a tais codificações?
Respostas resumo:
No caso geral, a resposta é NÃO.ML módulos fornecem funcionalidades (tais como especificação de compartilhamento por meio de assinaturas [1]) que não diretamente mapa .NET conceitos.
No entanto, para determinados casos de uso o ML expressões idiomáticas podem ser traduzidas.Esses casos incluem não apenas o básico Set
functor [2], mas também a functorial codificação de mônadas [3] e ainda mais avançada usa de som, tais como, finalmente, tagless intérpretes [4, 5].
Prática codificações exigir compromissos, tais como semi-seguro downcasts.Sua milhagem vai desconfiar.
Blogs e de código:
Solução
Um dos principais recursos dos módulos ML está compartilhando especificações. Não há nenhum mecanismo no .NET que seria capaz de imitá-los -. A maquinaria necessária é muito diferente
Você pode tentar fazê-lo girando os tipos compartilhados em parâmetros, mas isso não pode fielmente emular a capacidade de definir uma assinatura, e depois aplicar compartilhando a ele, talvez de várias maneiras diferentes.
Na minha opinião, .NET se beneficiaria de algo que tinha este tipo de máquinas - seria então aproximar-se verdadeiramente apoiar a diversidade de línguas modernas. Esperemos incluindo avanços mais recentes em sistemas de módulos como aqueles em MixML, que na minha opinião é o futuro dos sistemas de módulos. http://www.mpi-sws.org/~rossberg/mixml/
Outras dicas
HigherLogics é o meu blog, e eu passei muito tempo a investigar esta questão.A limitação é, de fato, abstração sobre o tipo de construtores, também conhecido como "genéricos sobre genéricos".Parece que o melhor que você pode fazer para imitar ML e módulos de ficheiro requer pelo menos um (semi-safe) cast.
Basicamente, ele vem para baixo para definir um tipo abstrato, e uma interface que corresponde ao módulo de assinatura que opera sobre que tipo.O resumo tipo e a interface compartilhar um parâmetro de tipo B, o que chamo de uma "marca";a marca é, geralmente, apenas o subtipo que implementa o módulo de interface.A marca garante que o tipo de passado é adequada subtipo esperado pelo módulo.
// 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; }; }
}
}
Como você pode ver, o elenco é composto principalmente de segurança, uma vez que o tipo de sistema garante a marca do tipo de expressão coincide com a marca do intérprete.A única forma de parafuso isso, é se o cliente cria a sua própria Exp de classe e especifica o Intérprete da marca.Existe um seguro de codificação que evita esse problema também, mas é muito pesado para um processo de programação.
Mais tarde eu usado esta codificação e traduzido exemplos a partir de um dos Oleg papéis escritos em MetaOCaml, para usar o C# e Linq.O intérprete pode, de forma transparente, a execução de programas escritos usando este incorporado linguagem do lado do servidor em ASP.NET ou client-side, como JavaScript.
Esta abstração sobre intérpretes é um recurso de Oleg final tagless de codificação.Links para o seu papel e são fornecidos em um post no blog.
Interfaces são de primeira classe .LÍQUIDO, e, uma vez que usar interfaces para codificar módulo de assinaturas, módulos e módulo de assinaturas também são de primeira classe neste codificação.Assim, o ficheiro basta usar a interface diretamente no lugar do módulo de assinaturas, ou seja,.eles iriam aceitar uma instância de ISymantics<B> e delegar as chamadas para ele.
Eu não sei functors ML bem o suficiente para realmente responder a sua pergunta. Mas vou dizer o fator limitante da Net eu sempre encontrar com monádico programação é a incapacidade de mais abstrato 'M' no sentido de "forall M. alguma expressão tipo com M < T> "(por exemplo, onde M é um construtor de tipo (tipo que leva um ou argumentos mais genéricos)). Então, se isso é algo que às vezes precisam / uso com functors, então me sinto muito confiante de que não há nenhuma boa maneira de expressá-lo na Net.
Eu já postou uma descrição detalhada da minha tradução de módulos mL, assinaturas e functors a um C # codificação equivalente. Espero que alguém acha útil.
O comentário de Brian no local. Aqui está o código OCaml que usa functors para dar uma implementação (estrita) de Haskell sequence :: (Monad m) => [m a] -> m [a]
parametrizados sobre a Mônada em questão:
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
Isso parece difícil de expressar em .NET.
Atualizar :
Usando uma técnica por naasking
eu era capaz de codificar a função sequence
reutilizável em F # em uma maneira de tipo seguro na sua maioria (usos operações de downcast).