44 votes

Comment implémenter des graphes et des algorithmes de graphes dans un langage de programmation fonctionnel?

En gros, je sais comment créer le diagramme de structures de données et l'utilisation de l'algorithme de Dijkstra dans les langages de programmation où les effets secondaires sont autorisés. Généralement, les algorithmes de graphes à utiliser une structure pour marquer certains nœuds que "visité", mais cela a des effets secondaires, que j'essaie d'éviter.

Je ne peux penser à une façon de l'implémenter dans un langage fonctionnel, mais il nécessite fondamentalement passant autour de grandes quantités de l'etat à des fonctions différentes, et je me demandais si il y a un plus d'espace-solution efficace.

17voto

Antal S-Z Points 17977

Vous pouvez vérifier comment Martin Erwig du Haskell fonctionnelle graphique de la bibliothèque fait des choses. Par exemple, son chemin le plus court fonctions sont toutes pures, et vous pouvez voir le code source de la façon dont il est mis en œuvre.

Une autre option, comme fmark mentionné, est d'utiliser une abstraction qui permet de mettre en oeuvre les fonctions pures en termes d'état. Il mentionne l'État de monade (qui est disponible dans les paresseux et stricte variétés). Une autre option, si vous travaillez dans le GHC Haskell compilateur/interpréteur (ou, je pense, tout Haskell mise en œuvre qui prend en charge le classement-2 types), une autre option est la ST monade, qui vous permet d'écrire des fonctions pures qui traitent des variables mutables en interne.

3voto

fmark Points 15028

Si vous avez été en utilisant haskell, le seul langage fonctionnel avec lequel je suis familier, je recommande l'utilisation de l' État de monade. L'État de monade est une abstraction pour une fonction qui prend un état et renvoie une valeur intermédiaire et de quelques nouvelles de l'état de la valeur. Ceci est considéré comme idiomatiques haskell pour les situations où le maintien d'un grand état est nécessaire.

Il est beaucoup plus agréable alternative à la naïve "retour de l'état comme un résultat de la fonction et de le passer comme paramètre" l'idiome qui est souligné en débutant en programmation fonctionnelle des tutoriels. J'imagine que la plupart des langages de programmation fonctionnelle en ai un similaire de construire.

2voto

Norman Ramsey Points 115730

Je viens de continuer à le visité définir comme un ensemble et passer en tant que paramètre. Il y a efficace log-temps implémentations de jeux de a commandé le type et extra-efficace des ensembles d'entiers.

Pour représenter un graphe-je utiliser les listes d'adjacence, ou je vais utiliser un fini de carte des cartes à chaque nœud de la liste de ses successeurs. Cela dépend de ce que je veux faire.

Plutôt que d'Abelson et Sussman, je vous recommande de Chris Okasaki est Purement Fonctionnelle des Structures de Données. Je suis lié à Chris de la thèse, mais si vous avez l'argent, il a développé dans un excellent livre.


Juste pour sourire, voici un peu effrayant inverse postorder la profondeur de recherche est réalisé dans le prolongement de passage de style en Haskell. C'est tout droit sorti de la Hoopl optimiseur de la bibliothèque:

postorder_dfs_from_except :: forall block e . (NonLocal block, LabelsPtr e)
                          => LabelMap (block C C) -> e -> LabelSet -> [block C C]
postorder_dfs_from_except blocks b visited =
 vchildren (get_children b) (\acc _visited -> acc) [] visited
 where
   vnode :: block C C -> ([block C C] -> LabelSet -> a) 
                      -> ([block C C] -> LabelSet -> a)
   vnode block cont acc visited =
        if setMember id visited then
            cont acc visited
        else
            let cont' acc visited = cont (block:acc) visited in
            vchildren (get_children block) cont' acc (setInsert id     visited)
      where id = entryLabel block
   vchildren bs cont acc visited = next bs acc visited
      where next children acc visited =
                case children of []     -> cont acc visited
                                 (b:bs) -> vnode b (next bs) acc     visited
   get_children block = foldr add_id [] $ targetLabels bloc
   add_id id rst = case lookupFact id blocks of
                      Just b -> b : rst
                      Nothing -> rst

0voto

Greg Points 4537

J'aimerais entendre parler de certains vraiment intelligent de la technique, mais je pense qu'il y a deux approches fondamentales:

  1. Modifier une partie de l'état global de l'objet. c'est à dire les effets secondaires
  2. Passer le graphique en tant qu'argument à vos fonctions avec le retour de la valeur de la modification de la graphique. Je suppose que c'est votre approche de "faire passer autour de grandes quantités d'etat"

Qu'est ce qui est fait dans la programmation fonctionnelle. Si le compilateur/interpréteur est tout bon, il va l'aider à gérer la mémoire pour vous. En particulier, vous voulez vous assurer que vous utilisez la queue de la récursivité, si vous le répéter dans l'un de vos fonctions.

-1voto

Vlad Points 3199

La plupart des langages fonctionnels de support intérieure fonctions. Ainsi, vous pouvez tout simplement créer votre représentation graphique dans la couche la plus externe et juste référence à partir de l'intérieur de la fonction.

Ce livre couvre largement http://www.amazon.com/gp/product/0262510871/ref=pd_lpo_k2_dp_sr_1?ie=UTF8&cloe_id=aa7c71b1-f0f7-4fca-8003-525e801b8d46&attrMsgId=LPWidget-A1&pf_rd_p=486539851&pf_rd_s=lpo-top-stripe-1&pf_rd_t=201&pf_rd_i=0262011530&pf_rd_m=ATVPDKIKX0DER&pf_rd_r=114DJE8K5BG75B86E1QS

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X