variable valor utilizar una significa qué que pseudocodigo por inicializar inicialización formas declara debe cómo como asignarle asigna antes random functional-programming frp elm

random - significa - por que no se debe utilizar una variable antes de asignarle un valor



¿Cuál es la forma correcta de inicializar una aplicación de olmo? (4)

La documentación para el módulo de Elm Random dice:

Una buena manera de obtener una semilla inesperada es usar la hora actual. http://package.elm-lang.org/packages/elm-lang/core/1.1.0/Random

No veo, sin embargo, un buen ejemplo de cómo realizar dicha lógica de inicialización en la aplicación FRP. ¿A qué señal debo reaccionar? Cómo hacerlo con un mínimo de código y máximo de claridad.


Hay maneras diferentes de hacer esto. Cada uno tiene sus propios beneficios. Te daré los tres que conozco con un ejemplo similar para cada uno.

1) Añadir una entrada de marcador de tiempo

Una cosa que podría hacer es agregar tiempo a las entradas de su programa. Un ejemplo de un pequeño programa que usa la hora actual cada segundo para un número aleatorio:

import Time import Time (Time, second) import Text (asText) import Mouse import Signal import Signal (Signal, (<~), (~)) import Random import Random (Seed) import Graphics.Element (Element) randomInt : Seed -> Int randomInt seed = seed |> (Random.generate <| Random.int 1 10) |> fst otherInput : Signal (Int,Int) otherInput = Mouse.position timeSeed : Signal Seed timeSeed = Random.initialSeed << round <~ Time.every second inputs : Signal (Seed,(Int,Int)) inputs = (,) <~ timeSeed ~ otherInput update : (Seed, (Int,Int)) -> (Int,Int) -> (Int,Int) update (seed,(x,y)) (x'',y'') = let num = randomInt seed in (x-x''-num,y''-y+num) -- this update function is nonsense main : Signal Element main = asText <~ Signal.foldp update (0,0) inputs

Si necesita tiempo como una entrada de todos modos, y muestre sus otras entradas basadas en este tiempo, es la forma más fácil. (Si ya usa Time.fps para esto, use Time.timestamp para obtener la hora real)

2) Al inicio con una señal.

Si normalmente no necesita tiempo como entrada para su programa, la solución anterior no es la ideal. Es posible que prefiera iniciar el estado de su programa con la hora de inicio del programa y no tener que ignorar un indicador de tiempo por el resto del tiempo que se ejecuta el programa.

Probablemente sea más fácil hacer esto con el paquete de señal adicional *. Use Signal.Time.startTime para obtener una señal que no marque pero que solo tenga la hora de inicio del programa como valor inicial. Use Signal.Extra.foldp'' para que pueda usar el valor inicial de sus entradas.

import Time import Time (Time, second) import Text (asText) import Mouse import Signal import Signal (Signal, (<~), (~)) import Random import Random (Seed) import Graphics.Element (Element) import Signal.Extra as SignalE import Signal.Time as Time randomInt : Seed -> (Int,Seed) randomInt seed = (Random.generate <| Random.int 1 10) |> fst otherInput : Signal (Int,Int) otherInput = Mouse.position startTimeSeed : Signal Seed startTimeSeed = Random.initialSeed << round <~ Time.startTime inputs : Signal (Seed,(Int,Int)) inputs = (,) <~ startTimeSeed ~ otherInput update (x,y) (seed,(x'',y'')) = let (num,seed'') = randomInt seed in (seed'',(x-x''-num,y''-y+num)) main : Signal Element main = asText <~ SignalE.foldp'' (snd >> update) identity inputs

* Puede que esté sesgado porque soy el autor del paquete vinculado. Pero no conozco otros paquetes que ofrezcan la misma funcionalidad.

3) Al inicio con un puerto.

Si encuentra que la solución anterior no es satisfactoria, ya que tiene esta Signal no cambio para agregar a su entrada, esta solución es para usted. Aquí usamos interoperabilidad de JavaScript para obtener el tiempo de inicio del programa, y ​​Elm lo aceptará como un valor constante (sin Signal ). El código de Elm se ve así:

import Time import Time (Time, second) import Text (asText) import Mouse import Signal (Signal, (<~)) import Random import Random (Seed) import Graphics.Element (Element) port startTime : Float randomInt : Seed -> (Int,Seed) randomInt seed = (Random.generate <| Random.int 1 10) |> fst startTimeSeed : Seed startTimeSeed = Random.initialSeed <| round startTime update (x,y) (seed,(x'',y'')) = let (num,seed'') = randomInt seed in (seed'',(x-x''-num,y''-y+num)) main : Signal Element main = asText <~ Signal.foldp update (startTimeSeed, (0,0)) Mouse.position

Entonces, ¿cuál es el inconveniente aquí? Necesitas escribir algún JavaScript. En lugar de la norma

<script>Elm.fullscreen(Elm.<YourModule>)</script>

, necesitas algo como esto en tu archivo html:

<script>Elm.fullscreen(Elm.<YourModule>, {startTime: Date.now()})</script>

Si elige de esta manera, tal vez sea una buena idea usar un número aleatorio de JavaScript como inicial inicial. He leído que eso es más seguro criptográficamente (exención de responsabilidad: no sé mucho acerca de criptografía). Entonces tendrías un port aRandomNumber : Int y {aRandomNumber: Math.floor((Math.random() - 0.5) * 4294967295)} .


Revisé el tercer ejemplo de @Apanatshka arriba, tratando de llegar a un código más simple que se parezca más a la arquitectura estándar, al menos como se ve en los videos de entrenamiento de Mike Clark, y se ejecuta bajo Elm 0.16. Aquí está la versión refactorizada que se me ocurrió:

module PortBasedRandom where import Mouse import Signal exposing (Signal, map) import Random exposing (Seed) import Graphics.Element exposing (Element, show) port primer : Float firstSeed : Seed firstSeed = Random.initialSeed <| round primer type alias Model = { nextSeed : Seed , currentInt : Int } initialModel : Model initialModel = { nextSeed = firstSeed , currentInt = 0 } randomInt : Model -> Model randomInt model = let (i, s) = Random.generate (Random.int 1 10) model.nextSeed in { model | nextSeed = s, currentInt = i } update : (Int, Int) -> Model -> Model update (_, _) model = randomInt model main : Signal Element main = Signal.foldp update initialModel Mouse.position |> map (/m -> show m.currentInt)

Esto necesita ayuda especial en el archivo HTML, así que aquí hay un archivo que contiene dos ejemplos:

<html> <head> <title></title> <script src="port_based_random.js"></script> </head> <body> <p>Move your mouse to generate new random numbers between 1 and 10 inclusive.</p> <script>Elm.fullscreen(Elm.PortBasedRandom, {primer: Date.now()})</script> <script>Elm.fullscreen(Elm.PortBasedRandom, {primer: Math.floor((Math.random() - 0.5) * 4294967295)})</script> </body> </html>


Si está utilizando StartApp, deberá utilizar un archivo HTML personalizado con

<script type="text/javascript"> var yourPgm = Elm.fullscreen(Elm.Main, {startTime: Date.now()}); </script>

Luego, para utilizar el tiempo de inicio como una semilla:

startTimeSeed : Seed startTimeSeed = Random.initialSeed <| round startTime app = StartApp.start { init = (init startTimeSeed, Effects.none) , update = update , view = view , inputs = [] }

Y luego en el código harás algo como

init : Seed -> List Int init seed = fst <| Random.generate intList seed

donde, por ejemplo:

intList : Random.Generator (List Int) intList = Random.list 5 (Random.int 0 100)


Solo una actualización para las personas que llegaron aquí desde Google como lo hice yo: la forma recomendada de hacerlo ahora es con flags lugar de ports . El código en las otras respuestas ni siquiera se compilará ahora.

https://guide.elm-lang.org/interop/javascript.html

HTML

<script> var app = Elm.Main.fullscreen({myRandomValue: Date.now()}); </script>

Olmo

type alias Model = { mySeed : String } type alias Flags = { myRandomValue : String } init : Flags -> ( Model, Cmd Msg ) init flags = { mySeed = flags.myRandomValue }

...

main : Program Flags Model Msg main = programWithFlags { view = view, init = init, update = update }