graph - 在 Elm 中管理不可能状态的好模式是什么?

标签 graph functional-programming elm

也许你能帮上忙。我是一名 Elm 初学者,我正在为一个相当平凡的问题而苦苦挣扎。我对 Elm 感到非常兴奋,而且我在较小的事情上相当成功,所以现在我尝试了一些更复杂的事情,但我似乎无法理解它。

我正在尝试在 Elm 中构建一些使用类似图形的底层数据结构的东西。我用这样的流畅/工厂模式创建图表:

sample : Result String MyThing
sample =
  MyThing.empty
    |> addNode 1 "bobble"
    |> addNode 2 "why not"
    |> addEdge 1 2 "some data here too"

当此代码返回 Ok MyThing 时, 那么整个图已经以一致的方式建立起来, 有保证, 即所有节点和边都具有所需的数据, 并且所有节点的边都实际存在。

实际代码具有与节点和边关联的更复杂的数据,但这对问题无关紧要。在内部,节点和边存储在 Dict Int element 中.

type alias MyThing =
  { nodes : Dict Int String
  , edges : Dict Int { from : Int, to : Int, label : String } 
  }

现在,在模块的用户中,我想访问图形的各种元素。但是每当我使用 Dict.get 访问其中一个节点或边缘时, 我得到一个 Maybe .这相当不方便,因为凭借我的构造函数代码,我知道索引存在等。我不想用 Maybe 使上游代码困惑。和 Result当我知道边缘中的索引存在时。举个例子:

getNodeTexts : Edge -> MyThing -> Maybe (String, String)
getNodeTexts edge thing =
  case Dict.get edge.from thing.nodes of
    Nothing ->
      --Yeah, actually this can never happen...
      Nothing
    Just fromNode -> case Dict.get edge.to thing.nodes of
      Nothing -> 
        --Again, this can never actually happen because the builder code prevents it.
        Nothing
      Just toNode ->
        Just ( fromNode.label, toNode.label )

这只是很多样板代码,用于处理我在工厂代码中特别阻止的事情。但更糟糕的是:现在消费者需要额外的样板代码来处理 Maybe --可能不知道 Maybe实际上永远不会Nothing . API 有点欺骗消费者。这不是 Elm 试图避免的事情吗?与假设但不正确的比较:

getNodeTexts : Edge -> MyThing -> (String, String)
getNodeTexts edge thing =
  ( Dict.get edge.from thing.nodes |> .label
  , Dict.get edge.to thing.nodes |> .label 
  )

另一种方法是不使用 Int ID 而不是使用实际数据——但是更新内容变得非常乏味,因为连接器可能有很多边缘。通过 Int 在不解耦的情况下管理状态这似乎不是个好主意。

我觉得必须使用不透明的 ID 类型来解决这个难题,但我只是没有看到。如果有任何指点,我将不胜感激。

注意:我也尝试同时使用 drathierelm-community榆 TreeMap 形库,但它们没有解决具体问题。他们依靠Dict在下面,所以我最终得到了相同的 Maybe

最佳答案

您的问题没有简单的答案。我可以提供一条评论和编码建议。

您使用了神奇的词“不可能的状态”,但正如 OOBalance 所指出的,您可以在您的建模中创建一个不可能的状态。 Elm 中“不可能状态”的正常含义恰恰与建模有关,例如当您使用两个 Bool 来表示 3 种可能的状态时。在 Elm 中,您可以为此使用自定义类型,而不是在代码中留下一个 bool 组合。

至于你的代码,你可以减少它的长度(和复杂性)

getNodeTexts : Edge -> MyThing -> Maybe ( String, String )
getNodeTexts edge thing =
    Maybe.map2 (\ n1 n2  -> ( n1.label, n2.label ))
        (Dict.get edge.from thing.nodes)
        (Dict.get edge.to thing.nodes) 

关于graph - 在 Elm 中管理不可能状态的好模式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59620114/

相关文章:

ios - 如何绘制水平条形图而不显示轴

scala - 副作用是纯函数中找不到的一切吗?

elm - 使用 Elm 0.19.1 安装 NoRedInk/elm-decode-pipeline 时出错

elm - Elm 中解码超过 8 个字段的对象

c++ - 如何将邻接矩阵转换为关联矩阵,反之亦然?

algorithm - 调度应用中的约束图变换

python - 有没有一种简单易用的方法来可视化高维数据?

list - F#中元素的最优雅组合

javascript - Pointfree 在 Ramda 中通过对象中的键将数组连接到字符串

elm - 如何在此榆树效果示例中添加第二个骰子?