2016-11-15 2 views
0

Angesichts der folgenden Struktur des Dateisystems:Elm: wie Dict innerhalb Dict aktualisieren, wenn die Struktur dynamisch ist (hat unterschiedliche Tiefe)?

type alias FolderName = String 

type Folder 
    = Folder 
     { folderName : String 
     , childFolders : Dict FolderName Folder 
     } 

type alias FileSystem = 
    Dict FolderName Folder 


fileSystem : FildeSystem 
fileSystem = 
    Dict.formList 
     [ ("parent1" 
      , Folder 
       { folderName = "parent1" 
       , childFolders = 
        Dict.fromList 
         [ ("child1", Folder { folderName = "child1", childFolders = Dict.empty }) 
         , ("child2", Folder { folderName = "child2", childFolders = Dict.empty }) 
         , ("child3" 
          , Folder 
           { folderName = "child3" 
           , childFolders = 
            Dict.formList 
             [ ("sub-child_of_child3", Folder { folderName = "sub-child_of_child3", childFolders = Dict.empty }) 
             ] 
           } 
         ) 
         ] 
       } 
     ) 
     ] 

Ich möchte neue Ordner erstellen dynamisch der Lage sein, durch eine Funktion und Aufruf in der Lage vorbei, wo ich der neue Ordner erstellt werden soll. Der Ordnername und auch das FileSystem Dict. Etwas wie folgt aus:

createFolder: String -> FileSystem -> FolderName -> FileSystem 
createFolder "parent1/child3/sub-child_of_child3" fileSystem "DynamicallyCreated" 

Da es keine Möglichkeit im Voraus zu wissen, was die fileSystem Dict aussieht, und weil diese Ulme ist (no for loops) - ich denke, der einzige Weg, dies zu tun, ist Rekursion.

Der Code:

createFolder location fileSystem newFolderName= 
    let 
     locationAsArray = String.split "/" location 
    in 
        // first find the dict value. (that is the value of 'sub-child_of_child3' key, inside 'child3' Dict.) 

     findDictValueBasedOnLocation locationAsArray fileSystem 

        // then update the 'sub-child_of_child3' by inserting the newFolder. 
      |> (\ x -> { x | childFolders = Dict.insert newFolderName Folder { folderName = newFolderName, childFolders = Dict.empty } x.childFolders 

        // but how to reconsturct the child3, partent1 and finally the fileSystem now? Because this function it's supose to return a new fileSystem that contains the newly created folder. 

entsprechenden dict mit Rekursion finden:

findDictValueBasedOnLocation listDictKeys currentDict = 
    let 
     currentKey = 
      List.head listDictKeys 

     remainingKeys = 
      List.tail listDictKeys 
    in 
     -- when there is only one element in the listDictKeys that is: ["sub-child_of_child3"]- the recursive call stops/ 
     if List.length listDictKeys == 1 then 
      Dict.get currentKey currentDict 
       |> Maybe.withDefault -- what to add here? 
     else 
      let 
       nextDict = 
        Dict.get currentKey currentDict 
         |> Maybe.withDefault --what to add here ?- don't know the type .. 
      in 
       -- recursive call with the remaining listDictKeys and nextDict which is in fact the current Dict value. 
       findDictValueBasedOnContext remainingKeys nextDict 

Sie 2 große Probleme hier sehen können:

  1. die Dict.get kehrt a Vielleicht und ich weiß nicht, wie ich mit Witz umgehen soll h das in der Rekursion.
  2. auch wenn ich den entsprechenden Teil des Dict finden und es durch Erstellen des neuen Ordners aktualisieren; - Wie aktualisiere ich, was ich jetzt auf den höheren Ebenen wie parent1 habe? ex: - bedenke, dass dieses Update auf Level bis zu 20 stattfinden kann. Wie sage ich Level 3 2, 1 über dieses Update?

Ich versuche nicht unbedingt, diesen Code arbeiten zu lassen. Ich habe einen anderen Ansatz, es ist sogar noch besser.

Und konnte keine Beispiele zum Aktualisieren oder Erstellen von Dicts innerhalb Dicts dynamisch finden.

Ich kämpfe dieses Problem für 2-3 Tage jetzt.

Zuerst habe ich versucht, Datensätze anstelle von Dicts - weil sie verschiedene Arten in ihnen ermöglichen. Aber ich konnte nicht record."someString" verwenden, um auf seinen Wert zuzugreifen - wie in Javascript. Also kein Glück mit Platten. Dicts scheinen vielversprechender zu sein .. hoffe, dass jemand weiß, wie man dieses Problem löst. Danke :)

Antwort

2

Dies ist eine nette Herausforderung! Zunächst einmal handelt es sich um rekursive Typen (more on those here). A Folder enthält eine Dict FolderName Folder, also brauchen Sie hier etwas starke Eingabe.

Und Sie suchen rekursive Updates auf einem Dict in einem Dict.

Im folgenden finden Sie eine Probenlösung Code, die Sie kopieren/Paste http://elm-lang.org/try

Das Innenleben der verschiedenen Funktionen im Code erklärt sich.

Einige Kommentare:

  • Für eine Dict Aktualisierung ist ein gemeinsames Muster einen Schlüssel zu liefern + Update-Funktion auf die gesamte Dict (see here für docs auf Dict.update). Dies ist effizienter, wenn der 3-Schritt-Ansatz 1) einen zu aktualisierenden Datensatz abruft, 2) den Datensatz ändert und 3) ihn zurücksetzt, wenn einer der Knoten in dem bereitgestellten Pfad fehlschlägt, dann die Funktion wird einfach eine unveränderte FileSystem
  • zurückkehren Wenn newFolderName bereits vorhanden ist, wird der gesamte vorhandene Ordner mit diesem Namen (inklusive aller Dateien)

this helps ersetzt werden einige der Funktionen in Elm zu verstehen.

Code-Beispiel:

import Html exposing (text) 
import Dict exposing (Dict) 

---- TYPES 
type alias FolderName = String 

type Folder 
    = Folder 
     { folderName : FolderName 
     , childFolders : FileSystem 
     } 

type alias FileSystem = 
    Dict FolderName Folder 


{- MAIN FUNCTION: 
takes the first element in the path 
and tries to do a recursive update on the children of the fileSystem 
-} 
insertFolder: String -> FolderName -> FileSystem -> FileSystem 
insertFolder path newFolderName fileSystem = 
    let 
    nodeList = String.split "/" path 
    in 
    case nodeList of 
     node :: rest -> 
     -- if we have nodes, do recursive update on folders 
     fileSystem 
     |> Dict.update node (Maybe.map <| updateNestedFolder newFolderName rest) 

     [] -> 
     -- no path, so the new folder must be a root folder 
     fileSystem 
     |> Dict.inset newFolderName (newFolder newFolderName) 

{- Recursive update function where the magic happens 
-} 
updateNestedFolder : FolderName -> List FolderName -> Folder -> Folder 
updateNestedFolder newFolderName nodeList (Folder { folderName, childFolders }) = 
    case nodeList of 
    nextLevel :: rest -> 
     -- as long as there is a nodelist, we try to find deeper level 
     let 
     -- do recursive update on the children 
     newChildFolders = 
      childFolders 
      |> Dict.update nextLevel (Maybe.map <| updateNestedFolder newFolderName rest) 
     in 
     -- return the updated folder 
     Folder 
      { folderName = folderName 
      , childFolders = newChildFolders 
      } 

    [] -> 
     -- this is the lowest level, so we need to add to this FileSystem 
     let 
     -- add newFolderName to the child folders 
     newChildFolders = 
      childFolders 
      |> Dict.insert newFolderName (newFolder newFolderName) 
     in 
     -- return the folder 
     Folder 
      { folderName = folderName 
      , childFolders = newChildFolders 
      } 

---- HELPERS 

{- Create a new folder, without any children -} 
newFolder : String -> Folder 
newFolder folderName = 
    Folder 
    { folderName = folderName 
    , childFolders = Dict.empty 
    } 

------ EXAMPLE 


fileSystem = 
    Dict.fromList 
    [ ("parent1" 
     , Folder 
     { folderName = "parent1" 
     , childFolders = 
      Dict.fromList 
       [ ("child1" 
       , Folder 
        { folderName = "child1", childFolders = Dict.empty } 
       ) 
       , ("child2" 
       , Folder 
        { folderName = "child2", childFolders = Dict.empty } 
       ) 
       , ("child3" 
       , Folder 
        { folderName = "child3" 
        , childFolders = 
         Dict.fromList 
         [ ("sub-child_of_child3" 
          , Folder 
          { folderName = "sub-child_of_child3" 
          , childFolders = Dict.empty } 
         ) 
         ] 
        } 
       ) 
       ] 
      } 
     ) 
     ] 

main = 
    text <| toString <| 
    insertFolder 
     "parent1/child3/sub-child_of_child3" 
     "DynamicallyCreated" 
     fileSystem 
+0

Sie sind so klug Mann! :)) Vielen Dank, du hast mich gerettet. Ich werde dir zeigen, wofür ich das benutze - sobald es vorzeigbar wird. In erster Linie geht es um die Programmierung in Ulme mit Sprachbefehlen. Vielleicht hilfst du mir, einige Ideen umzugestalten, sobald das erste Demo funktioniert ... ok, viel Glück! – AIon

+0

Gern geschehen. Immer froh zu helfen! – wintvelt

0

Die Antwort oben gearbeitet gegeben - aber wenn Sie ein Problem haben diese Idee um revolvierende (nicht unbedingt mit dicts) - es lohnt sich in how zippers work zu suchen.

Reißverschlüsse sind die empfohlene Art, diese Art des Gehens auf Diktaten, Listen, Bäumen zu machen. Mehr hier: Learn You A Haskel - Zippers - Am Ende ist die Dateisystem-Implementierung.

Verwandte Themen