使用 Elm 生成随机 UUIDv4

Generate random UUIDv4 with Elm

我正在尝试在循环中生成随机 UUID 的 v4:

    randomUuid =
         -- TODO: find a way to generate random uuid for variableId

    updatedVariables =              
         group.variables |> List.map (\variable -> { variable | id = randomUuid })

我阅读了 elm/random and elm/uuid 的文档,但找不到如何在不使用种子的情况下生成 UUID。

我唯一能做的就是:

newUuid : Random.Seed -> ( String, Random.Seed )
newUuid seed =
    seed
        |> Random.step UUID.generator
        |> Tuple.mapFirst UUID.toString

我看到 elm/random 是一个 independentSeed 函数,但我无法让它生成种子。

我试图用 randomUuid 实现的等效节点是:

const { uuid } = require('uuidv4');

const randomUuid = uuid();

我觉得我可能在这里遗漏了 Elm 中的一些重要概念,但我自己无法理解。任何帮助或指示将不胜感激。

生成随机值是一种效果,因此纯语言不能只执行它。

但是,有一个纯粹的随机版本,它使用随机种子。这些具有 属性 每次你使用相同的种子生成一个值时,你都会得到相同的值 - 因此这只是一个纯计算并且在纯上下文中完全没问题。

Elm 允许你像 Cmd 一样执行效果,你 return 从你的 initupdate 功能。因此,您的一个选择是始终 return Random.generate GotANewUUID UUID.generator 需要它之前,然后在处理 GotANewUUID 消息时执行计算。

另一种选择是跟踪随机种子。您可以从 Random.initialSeed 的确定性开始(可能不是您想要的 UUID,因为它们在您程序的每个 运行 上都完全相同),或者在您的 init 函数中你returnRandom.generate GotNewSeed Random.independentSeed。然后将种子存储在模型中。 每次需要生成新的 UUID 时,使用上面的 newUuid 函数,确保存储新的种子。

这是一个例子:

import Random
import UUID

type alias Thing = 
    { id : String
    -- , some other stuff
    }

type alias Model =
    { seed : Random.Seed
    , stuff : List Thing
    }

type Msg
    = GotNewSeed Random.Seed 
    | AddAThing Thing
    | AddABunchOfThings (List Thing)

init : () -> (Model, Cmd Msg)
init flags =
    ({ seed = Random.initialSeed 567876567 
    -- Let's start with a deterministic seed
    -- so you don't need to deal with Maybe Seed later
     , stuff = []
    }, Random.generate GotNewSeed Random.independentSeed
    )

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
        GotNewSeed seed ->
            ({model | seed = seed}, Cmd.none)
    
        AddAThing thing ->
            let
                (newId, newSeed) = 
                     newUuid model.seed
            in
            ({ model | stuff = { thing | id = newId } :: model.stuff
             , seed = newSeed }
            , Cmd.none
            )

         AddABunchOfThings things ->
             let
                 (newStuff, newSeed) =
                      List.foldl (\thing (stuff, seed) ->
                          newUuid seed
                              |> Tuple.mapFirst (\id -> 
                                  { thing | id = id } :: stuff
                              )
                      ) (model.stuff, model.seed) things
              in
              ({model | stuff = newStuff, seed = newSeed}, Cmd.none)