Question

Les foncteurs ML peuvent-ils être exprimés de manière pratique avec des interfaces .NET et des génériques? Existe-t-il un exemple d’utilisation avancée du foncteur ML qui défie de tels encodages?

Résumé des réponses :

Dans le cas général, la réponse est NON. Les modules ML fournissent des fonctionnalités (telles que le partage de spécifications via des signatures [ 1 ]) qui ne mappent pas directement aux concepts .NET.

Cependant, dans certains cas d'utilisation, les idiomes de ML peuvent être traduits. Ces cas incluent non seulement le foncteur Set de base [ 2 ], mais aussi le codage fonctionnel des monades [ 3 ], et des utilisations encore plus avancées de Haskell, telles que les interpréteurs finalement sans étiquette [ 4 , 5 ].

Des codages pratiques nécessitent des compromis tels que des retransmissions semi-sûres. Votre kilométrage sera prudent.

Blogs et code:

  1. blog.matthewdoig.com
  2. higherlogics.blogspot.com
  3. functor monad en F #
Était-ce utile?

La solution

L'une des principales caractéristiques des modules ML est le partage des spécifications. Il n’existe pas de mécanisme dans .NET capable de les imiter - la machine requise est trop différente.

Vous pouvez essayer de le faire en transformant les types partagés en paramètres, mais cela ne permet pas de reproduire fidèlement la possibilité de définir une signature, puis de lui appliquer ultérieurement le partage, peut-être de différentes façons.

À mon avis, .NET bénéficierait de quelque chose qui disposait de ce type de machine: il serait alors plus proche de la diversité des langues modernes. J'espère inclure des avancées plus récentes dans les systèmes de modules, comme celles de MixML, qui, à mon avis, est l'avenir des systèmes de modules.        http://www.mpi-sws.org/~rossberg/mixml/

Autres conseils

HigherLogics est mon blog et j'ai passé beaucoup de temps à enquêter sur cette question. La limitation est en effet l'abstraction sur les constructeurs de types, ou "génériques sur génériques". Il semble que le mieux que vous puissiez faire pour imiter les modules ML et les foncteurs nécessite au moins un transtypage (semi-sécurisé).

Cela revient essentiellement à définir un type abstrait et une interface qui correspond à la signature du module qui fonctionne sur ce type. Le type abstrait et l'interface partagent un paramètre de type B, que j'appelle une "marque"; la marque est généralement juste le sous-type qui implémente l'interface de module. La marque veille à ce que le type transmis soit le sous-type correct attendu par le module.

// 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; }; }
  }
}

Comme vous pouvez le constater, la distribution est généralement sécurisée, car le système de types garantit que la marque du type d'expression correspond à la marque de l'interprète. La seule façon de tout gâcher est que le client crée sa propre classe Exp et spécifie la marque Interpreter. Il existe un encodage plus sûr qui évite également ce problème, mais il est beaucoup trop lourd pour une programmation ordinaire.

J'ai plus tard utilisé cet encodage et traduit les exemples d'un des papiers d'Oleg écrits en MetaOCaml, pour utiliser C # et Linq. L’interprète peut exécuter en toute transparence des programmes écrits à l’aide de ce langage côté serveur intégré dans ASP.NET ou côté client au format JavaScript.

Cette abstraction sur les interprètes est une caractéristique du dernier codage sans étiquette d’Oleg. Des liens vers son article sont fournis dans l'article de blog.

Les interfaces sont de première classe dans .NET et, puisque nous utilisons des interfaces pour coder les signatures de module, les modules et les signatures de module sont également de première classe dans ce codage. Ainsi, les foncteurs utilisent simplement l'interface directement à la place des signatures de modules, c'est-à-dire. ils accepteraient une instance de ISymantics < B > et déléguer tous les appels.

Je ne connais pas assez bien les foncteurs ML pour vraiment répondre à votre question. Mais je dirai que le seul facteur limitatif de .Net que je trouve toujours avec la programmation monadique est l’incapacité d’abstraire sur «M» dans le sens de "forall M. une expression de type avec M < ; T > " (par exemple, où M est un constructeur de type (type qui prend un ou plusieurs arguments génériques)). Donc, si c'est quelque chose dont vous avez parfois besoin / que vous utilisez avec des foncteurs, alors je suis assez confiant qu'il n'y a pas de bon moyen de l'exprimer sur .Net.

Je viens de poster une description détaillée de ma traduction pour les modules ML, les signatures et les foncteurs vers un codage C # équivalent. J'espère que quelqu'un le trouvera utile.

Le commentaire de Brian est sur place. Voici le code OCaml qui utilise des foncteurs pour donner une implémentation (stricte) de Haskell sequence :: (Monad m) = > [m a] - > m [a] paramétré sur la monade en question:

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

Cela semble difficile à exprimer dans .NET.

MISE À JOUR :

En utilisant une technique de naasking , j'ai réussi à coder la fonction séquence réutilisable en F # de manière essentiellement sécurisée par le type (utilise des downcasts).

http://gist.github.com/192353

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top