This question already has answers here:
elm generate random number
(2 answers)
Closed 7 years ago.
What's a simple way to do this?
The documentation for Random.initialSeed says:
"A good way to get an unexpected seed is to use the current time."
http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Random#initialSeed
After a ton of reading, I can only find "solutions" that are well beyond my understanding of Elm and Functional Programming. They also don't seem to be solutions to this problem.
I'm currently hardcoding:
Random.initialSeed 314
If you use a library, please include the name used to get it from elm package. I've seen a solution that says use Native.now but I can't figure out how to get that one.
stackoverflow is suggesting this one but I can't understand how to apply it to my usecase Elm Current Date
You can try case nelson's answer from How do I get the current time in Elm?
From elm repl:
> import Now
> import Random
> Now.loadTime |> round -- get current time in Int
1455406828183 : Int
> Now.loadTime |> round |> Random.initialSeed -- get the Seed
Seed { state = State 1560073230 678, next = <function>, split = <function>, range = <function> }
: Random.Seed
I also have the code on my repo here.
Note: don't forget "native-modules": true in elm-package.json.
Edit:
to try the code,
git clone https://github.com/prt2121/elm-backup.git
cd elm-backup/now
elm make Now.elm
add "native-modules": true in elm-package.json
elm repl
The simplest way I can think of is to use the Elm Architecture and Effects.tick mechanism to initialise the seed with a time value.
Here is an example of how this works:
import Html exposing (..)
import Html.Events exposing (onClick)
import Random exposing (Seed, generate, int, initialSeed)
import Time exposing (Time)
import Effects exposing (Effects, Never)
import Task exposing (Task)
import StartApp
type alias Model = { seed : Seed, value : Int}
type Action = Init Time | Generate
init : (Model, Effects Action)
init = (Model (initialSeed 42) 0, Effects.tick Init)
modelFromSeed : Seed -> (Model, Effects Action)
modelFromSeed seed =
let
(value', seed') = generate (int 1 1000) seed
in
(Model seed' value', Effects.none)
update : Action -> Model -> (Model, Effects Action)
update action model =
case action of
Init time ->
modelFromSeed (initialSeed (round time))
Generate ->
modelFromSeed model.seed
view : Signal.Address Action -> Model -> Html
view address model =
div []
[ text ("Current value: " ++ (toString model.value))
, br [] []
, button [onClick address Generate] [text "New Value"]
]
app : StartApp.App Model
app = StartApp.start
{ init = init
, update = update
, view = view
, inputs = []
}
main : Signal Html
main = app.html
port tasks : Signal (Task Never ())
port tasks = app.tasks
Related
I'm toying around with Elm processes in order to learn more about how they work. In parts of this, I'm trying to implement a timer.
I bumped into an obstacle, however: I can't find a way to access the result of a process' task in the rest of the code.
For a second, I hoped that if I make the task resolve with a Cmd, the Elm runtime would be kind enough to perform that effect for me, but that was a naive idea:
type Msg
= Spawned Process.Id
| TimeIsUp
init _ =
( Nothing
, Task.perform Spawned (Process.spawn backgroundTask)
)
backgroundTask : Task.Task y (Platform.Cmd.Cmd Msg)
backgroundTask =
Process.sleep 1000
-- pathetic attempt to send a Msg starts here
|> Task.map ( always
<| Task.perform (always TimeIsUp)
<| Task.succeed ()
)
-- and ends here
|> Task.map (Debug.log "Timer finished") -- logs "Timer finished: <internals>"
update msg state =
case msg of
Spawned id ->
(Just id, Cmd.none)
TimeIsUp ->
(Nothing, Cmd.none)
view state =
case state of
Just id ->
text "Running"
Nothing ->
text "Time is up"
The docs say
there is no public API for processes to communicate with each other.
I'm not sure if that implies that a process can't cummunicate with the rest of the app.
Is there any way to have update function receive a TimeIsUp once the process exits?
There is one way but it requires a port of hell:
make a fake HTTP request from the process,
then intercept it via JavaScript
and pass it back to Elm.
port ofHell : (() -> msg) -> Sub msg
subscriptions _ =
ofHell (always TimeIsUp)
backgroundTask : Task.Task y (Http.Response String)
backgroundTask =
Process.sleep 1000
-- nasty hack starts here
|> Task.andThen ( always
<| Http.task { method = "EVIL"
, headers = []
, url = ""
, body = Http.emptyBody
, resolver = Http.stringResolver (always Ok "")
, timeout = Nothing
}
)
Under the hood, Http.task invokes new XMLHttpRequest(), so we can intercept it by redefining that constructor.
<script src="elm-app.js"></script>
<div id=hack></div>
<script>
var app = Elm.Hack.init({
node: document.getElementById('hack')
})
var orig = window.XMLHttpRequest
window.XMLHttpRequest = function () {
var req = new orig()
var orig = req.open
req.open = function (method) {
if (method == 'EVIL') {
app.ports.ofHell.send(null)
}
return orig.open.apply(this, arguments)
}
return req
}
</script>
The solution is not production ready, but it does let you continue playing around with Elm processes.
Elm Processes aren't a fully fledged API at the moment. It's not possible to do what you want with the Process library on its own.
See the notes in the docs for Process.spawn:
Note: This creates a relatively restricted kind of Process because it cannot receive any messages. More flexibility for user-defined processes will come in a later release!
and the whole Future Plans section, eg.:
Right now, this library is pretty sparse. For example, there is no public API for processes to communicate with each other.
Got a hopefully simple problem. When I receive action A in my update function, I'd like to return a task that does some stuff, then results in action B, which is received by the update function again. Its my understanding that whatever effects are returned from Update will be executed by startapp, but nothing seems to be happening. Here's a whittled down example:
import StartApp exposing (start)
import Effects
import Task
import Html exposing (..)
import Html.Events exposing (..)
main =
(start
{ init = init
, update = update
, view = view
, inputs = []
}).html
type Action
= Click
| Dummy
type alias Model =
{ clicks: Int
}
init : (Model, Effects.Effects Action)
init = (Model 0, Effects.none)
update : Action -> Model -> (Model, Effects.Effects Action)
update action model =
case action of
Click ->
-- the click is received.
(model, Effects.task (Task.succeed Dummy))
Dummy ->
-- this never happens!!
({ model | clicks = model.clicks + 1}, Effects.none)
view : Signal.Address Action -> Model -> Html
view address model =
let start = button [ onClick address Click ] [ text (toString model.clicks) ]
in
div [] ([start])
StartApp requires a port for tasks in addition to main. Change your main function and add the tasks port like this and you'll be all set:
app =
start
{ init = init
, update = update
, view = view
, inputs = []
}
main =
app.html
port tasks : Signal (Task.Task Effects.Never ())
port tasks =
app.tasks
In my Elm program, I'd like to initialize my model based on the query string.
For example, if the query string is ?w=3&h=5 I'd like to have:
initialModel =
{ width = 3
, height = 5
}
Is that possible to achieve this in Elm, or the only way to do this is to get the query parameters in Javascript and pass them via a port?
Elm 0.19
For elm 0.19 the below concept is the same. Both of these packages still exist but have been moved and relabeled as the official elm/url and elm/browser libraries.
Elm 0.18
This example uses evancz/url-parser and elm-lang/navigation. There are a few kinks that aren't straightforward in the documentation, but I've explained them briefly below. The example should speak for itself.
module Main exposing (..)
import Html as H exposing (..)
import Navigation exposing (Location)
import UrlParser as UP exposing ((</>), (<?>), top, parsePath, oneOf, s, stringParam, Parser)
import Maybe.Extra as MaybeExtra exposing (unwrap)
type Route
= UrlRoute (Maybe String) (Maybe String)
| NotFoundRoute
type Msg
= UrlParser Navigation.Location
type alias Model =
{ location : Route
, w : String
, h : String
}
type alias SearchParams =
{ w : Maybe String, h : Maybe String }
main =
Navigation.program UrlParser
{ init = init
, view = view
, update = update
, subscriptions = (\_ -> Sub.none)
}
init : Location -> ( Model, Cmd Msg )
init location =
let
currentPath =
parseLocation location
in
( initialModel currentPath
, Cmd.none
)
parseLocation : Location -> Route
parseLocation location =
case (parsePath matchers location) of
Just route ->
route
Nothing ->
NotFoundRoute
matchers : Parser (Route -> a) a
matchers =
UP.map UrlRoute (UP.s "index" <?> UP.stringParam "w" <?> UP.stringParam "h")
initialModel : Route -> Model
initialModel route =
{ location = route
, w = MaybeExtra.unwrap "" (\x -> Maybe.withDefault "" x.w) (parseParams route)
, h = MaybeExtra.unwrap "" (\x -> Maybe.withDefault "" x.h) (parseParams route)
}
parseParams : Route -> Maybe SearchParams
parseParams route =
case route of
UrlRoute w h ->
Just { w = w, h = h }
NotFoundRoute ->
Nothing
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
UrlParser location ->
( model
, Cmd.none
)
view : Model -> Html msg
view model =
div []
[ h1 [] [ text "URL Info" ]
, div [] [ text ("W is: " ++ model.w) ]
, div [] [ text ("H is: " ++ model.h) ]
]
The "trick" is to create another type alias to place your query params inside of. In the above example I've created the type SearchParams. After creating this type we just use an initialModel that takes in the currentPath.
From there, our model can extract the query params with Maybe.withDefault (it needs to be a Maybe type because the params may not be there). Once we have our data in the model we just print it out in the view.
Hope this helps!
There is no built-in core library way to access the URL. You can use ports and the community library jessitron/elm-param-parsing.
If you also want to set the URL, you can again use ports, or you can use the History API, for which there are bindings in TheSeamau5/elm-history.
Unfortunately jessitron/elm-param-parsing doesn't work with Elm 0.18.
Use elm-lang/navigation package:
http://package.elm-lang.org/packages/elm-lang/navigation/latest/Navigation
https://github.com/elm-lang/navigation/tree/2.1.0
especially this function:
program
: (Location -> msg)
-> { init : Location -> (model, Cmd msg), update : msg -> model -> (model, Cmd msg), view : model -> Html msg, subscriptions : model -> Sub msg }
-> Program Never model msg
In the second parameter you can see "init : Location -> (model, Cmd msg)". This should handle reading of initial URL. To complement that, first parameter is a function which gets called every time URL changes.
(I am aware it's an old question, but this link popped out when I was looking for the solution to the same problem and accepted answer didn't help)
How can I make two independent action inside one function in Elm? Is there any pattern or explicit function?
Generally speaking I'm not sure how to implement ajax data loading inside Elm Architecture.
For example I'd like to make Http.get and return modified argument function like this
fetchCustomers model =
Http.get parseCustomers "/customers" `andThen` setCustomers
{ model | fetchingCustomers <- True }
TL;DR
You do so by returning both in a tuple. Then you split the signal from your update in foldp, put the model part in the view function and put the tasks in a port to execute. This is alluded to in the Architecture post at the end under One Last Pattern.
Longer answer
Since you link to the Elm Architecture, let me link to that too, but in particular the last part: One Last Pattern.
What you want to do here is part of the "update" of your program, where you not only update your model but also do something else on the side. Therefore you do not just return the new model, but also the extra thing you want to do (in this case an Http request):
fetchCustomers model =
( { model | fetchingCustomers <- True }
, Http.get parseCustomers "/customers" `andThen` setCustomers
)
Instead of using StartApp like the architecture page does, you can paste in the start function from the package. Now you have access to the mailbox where the actions are coming from, so you can pass it to your update so you can send your Http results there too. And you can split the tuple that you're returning from the update function to actually execute the tasks:
start app =
let
actions =
Signal.mailbox Nothing
address =
Signal.forwardTo actions.address Just
model =
Signal.foldp
(\(Just action) (model,_) -> app.update actions action model)
-- ignore task: ^ ^^^ ^^^^^^^^:add mailbox
app.model
actions.signal
in
(Signal.map (fst >> app.view address) model, Signal.map snd model)
-- ^ ^^^^^^^ :split model: ^^^^^^^^^^^^^^^^^^^^^^^
fetchCustomers actions model =
( { model | fetchingCustomers <- True }
, Http.get parseCustomers "/customers"
`andThen` (SetCustomers >> Signal.send actions.address)
-- use mailbox to send Http results as an input action again
)
-- larger update function you probably have
update actions action model = case action of
-- ...
SetCustomers cust -> setCustomers cust
-- ...
-- fetchCustomers actions model
(output, tasks) = start { model: model, view: view, update: update }
-- task execution:
port httpGets = tasks
-- output your view
main = output
You can find more examples of doing Http on the website under "tasks".
Every time I run "quickCheck prop_xyz", a new random seed is used. How do I enforce QuickCheck to always use the same random seed?
Thanks!
The functionality you need is in Test.QuickCheck; use quickCheckWith to specify custom Args. In particular, there's the replay :: Maybe (StdGen, Int) field, which allows you to replay tests. So you can use the stdArgs defaults and tweak them; for instance,
ghci> :load Main.hs
ghci> import Test.QuickCheck
ghci> import System.Random -- for mkStdGen
ghci> quickCheckWith stdArgs{replay = Just (mkStdGen 42, 0)} prop_xyz
The second component of the tuple has to do with the size of the test cases, but I forget exactly what.
Use the quickCheckWith function
quickCheckWith (stdArgs{replay = Just (myNewGen, testSize)}) property
If you have a test that's failing and you want to reuse it,
result <- quickCheckResult failing_prop
let gen = usedSeed result
let size = usedSize result
to get the size and seed used in a failing test.
Since you also want reproducible errors, a good shrinking algorithm may help. By default it returns [] but provide a nice enough one, then you can end up with the same (minimal) failures even on different random runs.
Example with QuickCheck >= 2.7 and tf-random.
If the output of your failing test run looks something like this:
Failure {
usedSeed = TFGenR 1CE4E8B15F9197B60EE70803C62388671B62D6F88720288F5339F7EC521FEBC4 0 70368744177663 46 0,
USEDSIZE = 75,
...
}
Then you can reproduce the failure as follows:
import Test.QuickCheck.Random (QCGen(..))
import System.Random.TF (TFGen)
qcheck :: Testable a => a -> IO ()
qcheck prop = quickCheckWith args prop
where
usedSeed = QCGen (read "TFGenR 1CE4E8B15F9197B60EE70803C62388671B62D6F88720288F5339F7EC521FEBC4 0 70368744177663 46 0"::TFGen)
usedSize = 75
args = stdArgs{
replay=Just(usedSeed, usedSize)
}
If you want to determine the Generator that caused the failure you could do the following:
import Test.QuickCheck
import System.Random
reproducableTest :: Testable a => a -> Maybe (StdGen, Int) -> IO ()
reproducableTest prop repl = do result <- quickCheckWithResult stdArgs{replay = repl} prop
case result of
Failure{interrupted = False} -> do putStrLn $ "Use " ++ show (usedSeed result) ++ " as the initial seed"
putStrLn $ "Use " ++ show (usedSize result) ++ " as the initial size"
_ -> return ()
Only the first of the two seed numbers should be used as an argument for the function.
So if you have your property prop, your initial call would be reproducableTest prop Nothing. You will get something like
Use x y as the initial seed
Use z as the initial size
Then you would call again with reproducableTest prop $ Just (mkStdGen x , z)