什么是初始化榆树应用程序的正确方法 [英] What is the correct way of initializing an elm application

查看:98
本文介绍了什么是初始化榆树应用程序的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Elm的 Random 模块的文档声明:


获得意想不到的种子是使用当前时间。
http://package.elm-lang.org/packages/ elm-lang / core / 1.1.0 / Random

我没有看到一个很好的例子,在FRP应用程序中执行这种初始化逻辑。我应该对什么信号做出反应?如何用最少的代码和最大的清晰度来做到这一点。

解决方案

有不同的方法可以做到这一点。每个人都有自己的好处。我会给你我知道的三个,每个都有类似的例子。

1)添加时间报价输入



您可以做的一件事是为您的输入添加时间程序。

  import Time 
import Time(时间,秒)
导入文本(asText)
导入鼠标
导入信号
导入信号(Signal,(<〜),(〜))
import Random
import Random(Seed)
import Graphics.Element(Element)

randomInt:Seed - > Int
randomInt seed = seed |> (Random.generate< | Random.int 110)|> 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

更新:(种子,(Int,Int)) - > (Int,Int) - > (x,y)=
let num = randomInt seed
in(x-x'-num,y) '-y + num) - 这个更新函数是废话

main:信号元素
main = asText<〜Signal.foldp更新(0,0)输入

无论如何,如果您需要时间作为输入,并根据这段时间对其他输入进行采样,这是最简单的方法。 (如果您已经使用 Time.fps 为此,请使用 Time.timestamp 来获得实际的时间)



2)在信号

如果您通常不需要时间作为程序的输入,则以前的解决方案并不理想。您可能更愿意使用程序的开始时间初始化程序状态,而不必在程序运行的其余时间忽略时间报警。

使用信号额外包裹 *。使用 Signal.Time.startTime 得到一个不打勾的信号,但只有程序的开始时间作为初始值。使用 Signal.Extra .foldp' ,以便您可以使用输入的初始值。

 导入时间
导入时间(时间,秒)
导入文本(asText)
导入鼠标
导入信号
导入信号(信号,(&〜),(〜))
导入随机
导入随机(种子)
导入Graphics.Element (元素)
导入Signal.Extra作为SignalE
导入Signal.Time作为时间

randomInt:Seed - > (Int,Seed)
randomInt seed =(Random.generate< | Random.int 110)|> 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

(seed),(x-x'-num,y)中的update(x,y)(seed,(x',y'))=
let(num,seed')= randomInt seed
'-y + num))

main:Signal Element
main = asText<〜SignalE.foldp'(snd> update)identity inputs

*我可能有偏见,因为我是链接包的作者。但我不知道提供相同功能的其他软件包。

3)使用端口启动



如果您发现以前的解决方案不理想,因为您没有 - 改变 Signal 以添加到您的输入中,该解决方案适合您。在这里,我们使用 JavaScript interop 来获取程序启动时间,Elm会接受它作为一个常量值(no 信号)。 Elm代码如下所示:

  import Time 
import Time(time,second)
import Text (asText)
导入鼠标
导入Signal(Signal,(〜))
导入Random
导入Random(Seed)
导入Graphics.Element(Element)

port startTime:Float

randomInt:Seed - > (Int,Seed)
randomInt seed =(Random.generate< | Random.int 110)|> fst

startTimeSeed:Seed
startTimeSeed = Random.initialSeed< | (seed,'x',y'))=
let(num,seed')= randomInt seed
(seed, ,(x-x'-num,y'-y + num))

main:信号元素
main = asText<〜Signal.foldp update(startTimeSeed,(0,0 ))Mouse.position

那么这里有什么缺点?你需要编写一些JavaScript。而不是标准

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

,您需要在您的html文件中这样:

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

如果您选择这种方式,最好使用JavaScript中的随机数作为您的初始值种子。我读过这样的密码更安全(免责声明:我对密码不太了解)。所以你有一个 port aRandomNumber:Int {aRandomNumber:Math.floor((Math.random() - 0.5)* 4294967295)}

The documentation for Elm's Random module states:

A good way to get an unexpected seed is to use the current time. http://package.elm-lang.org/packages/elm-lang/core/1.1.0/Random

I don't see however a good example of how to perform such initialization logic in FRP application. What signal should I react to? How to do this with a minimum of code and maximum of clarity.

解决方案

There are different ways to do this. Each has it's own benefits. I'll give you the three that I know with a similar example for each.

1) Add a time ticker input

One thing you could do is add time to the inputs of your program. An example of a tiny program using the current time every second for a random number:

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

If you need time as an input anyway, and sample your other inputs based on this time, it's the easiest way. (If you already use Time.fps for this, use Time.timestamp to get the actual time with it)

2) At startup with a signal

If you don't normally need time as an input to your program, the previous solution is not ideal. You may prefer to initialise your program state with the start time of the program and not have to ignore a time ticker for the rest of the time the program runs.

It's probably easiest to do this with the signal-extra package*. Use Signal.Time.startTime to get a signal that doesn't tick but only has the start time of the program as the initial value. Use Signal.Extra.foldp' so you can use the initial value of your inputs.

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

*I may be biased because I'm the author of the linked package. But I don't know of other packages offering the same functionality.

3) At startup with a port

If you find the previous solution unsatisfactory, because you have this not-changing Signal to add to your input, this solution is for you. Here we use JavaScript interop to get the program startup time, and Elm will accept it as a constant value (no Signal). The Elm code looks like so:

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

So what's the downside here? You need to write some JavaScript. Instead of the standard

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

, you need something like this in your html file:

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

If you choose this way, perhaps it's a good idea to use a random number from JavaScript as your initial seed. I've read that that's more cryptographically secure (disclaimer: I don't know much about crypto). So you'd have a port aRandomNumber : Int and {aRandomNumber: Math.floor((Math.random() - 0.5) * 4294967295)}.

这篇关于什么是初始化榆树应用程序的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆