Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elm:如果结构是动态的(具有不同的深度),如何在Dict内部更新Dict?_Elm - Fatal编程技术网

Elm:如果结构是动态的(具有不同的深度),如何在Dict内部更新Dict?

Elm:如果结构是动态的(具有不同的深度),如何在Dict内部更新Dict?,elm,Elm,给定以下文件系统结构: type alias FolderName = String type Folder = Folder { folderName : String , childFolders : Dict FolderName Folder } type alias FileSystem = Dict FolderName Folder fileSystem : FildeSystem fileSystem =

给定以下文件系统结构:

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 } )
                                        ]
                                }
                          )
                        ]
                }
          )
        ]
我希望能够通过调用函数并传入要创建新文件夹的位置动态创建新文件夹。。文件夹的名称以及文件系统Dict。大概是这样的:

createFolder: String -> FileSystem -> FolderName -> FileSystem
createFolder "parent1/child3/sub-child_of_child3" fileSystem "DynamicallyCreated"
因为无法预先知道
文件系统Dict
是什么样子,而且因为这是elm(
no for loops
)-我认为唯一的方法是使用递归

代码:

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. 
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
使用递归查找相应的dict:

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. 
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
您可以在这里看到两大问题:

  • get返回一个Maybe,我不知道如何在递归中处理它
  • 即使我设法找到Dict的相应部分并通过创建新文件夹来更新它;-如何在更高级别(如
    parent1
    )上更新现有内容?例:-请记住,此更新可能会发生在20级。。我如何告诉3级2,1关于此更新
  • 我不一定要让这段代码工作。我想你有另一种方法,甚至更好

    在Dicts中找不到动态更新或创建Dicts的示例

    我现在和这个问题斗争了2-3天

    首先,我尝试使用记录而不是Dicts,因为它们允许不同类型的记录。但是我不能使用
    record.“someString”
    来访问它的值,就像在javascript中一样。所以没有记录。格言似乎更有前途。。希望有人知道如何解决这个问题。谢谢:)

    这是一个很好的挑战! 首先,您要处理递归类型()。一个
    文件夹
    包含一个
    Dict FolderName文件夹
    ,因此您确实需要在这里进行一些强输入

    您希望在
    Dict
    中的
    Dict
    上执行递归更新

    在下面,您可以找到一个示例解决方案代码,您可以将其复制/粘贴到其中

    代码本身解释了不同函数的内部工作原理

    一些评论:

    • 对于更新
      Dict
      ,一种常见模式是为整个
      Dict
      (对于
      Dict.update
      上的文档)提供键+更新功能。这比以下三步方法更有效:1)检索要更新的记录,2)更改记录,3)将其放回
      Dict
    • 如果所提供路径中的任何节点出现故障,则该函数将只返回一个未更改的
      文件系统
    • 如果
      newFolderName
      已存在,则将替换具有该名称的整个现有文件夹(包括所有子文件夹)
    希望这有助于理解Elm中的一些函数

    代码示例:

    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
    
    导入Html(文本)
    导入Dict(Dict)
    ----类型
    类型别名FolderName=String
    类型文件夹
    =文件夹
    {folderName:folderName
    ,子文件夹:文件系统
    }
    类型别名文件系统=
    Dict FolderName文件夹
    {主要功能:
    获取路径中的第一个元素
    并尝试对文件系统的子文件执行递归更新
    -}
    insertFolder:String->FolderName->FileSystem->FileSystem
    insertFolder路径newFolderName文件系统=
    让
    nodeList=String.split“/”路径
    在里面
    案例节点列表
    节点::rest->
    --如果我们有节点,对文件夹进行递归更新
    文件系统
    |>Dict.update节点(Maybe.map
    --没有路径,因此新文件夹必须是根文件夹
    文件系统
    |>Dict.inset newFolderName(newFolder newFolderName)
    {-发生魔术的递归更新函数
    -}
    updateNestedFolder:FolderName->List FolderName->Folder->Folder
    updateNestedFolder newFolderName节点列表(文件夹{folderName,childFolders})=
    案例节点列表
    下一级::rest->
    --只要有一个节点列表,我们就试图找到更深层次的节点
    让
    --对子对象执行递归更新
    newChildFolders=
    子文件夹
    |>Dict.updatenextlevel(Maybe.map
    --这是最低级别,所以我们需要添加到这个文件系统中
    让
    --将newFolderName添加到子文件夹
    newChildFolders=
    子文件夹
    |>Dict.insert newFolderName(newFolder newFolderName)
    在里面
    --返回文件夹
    文件夹
    {folderName=folderName
    ,childFolders=newChildFolders
    }
    ----助手
    {-创建一个没有任何子文件夹的新文件夹-}
    新建文件夹:字符串->文件夹
    NewFolderFolderName=
    文件夹
    {folderName=folderName
    ,childFolders=Dict.empty
    }
    ------范例
    文件系统=
    口述从句表
    [(“父母1”
    ,文件夹
    {folderName=“parent1”
    ,子文件夹=
    口述从句表
    [(“儿童1”
    ,文件夹
    {folderName=“child1”,childFolders=Dict.empty}
    )
    ,(“儿童2”
    ,文件夹
    {folderName=“child2”,childFolders=Dict.empty}
    )
    ,(“儿童3”
    ,文件夹
    {folderName=“child3”
    ,子文件夹=
    口述从句表
    [(“儿童3的子儿童”
    ,文件夹
    {folderName=“子女3的子子女”
    ,childFolders=Dict.empty}
    )
    ]
    }
    )
    ]
    }
    )
    ]
    主要=
    
    text上面给出的答案是有效的-但是如果你有一个围绕这个想法的问题(不一定是dicts)-很值得研究
    拉链是如何工作的

    齐佩