I use float : Signal a -> Signal Float to generate random number.
I want to compare this generated number with a Float, how can I do that?
main = lift asText ((Random.float (fps 24)) < 0.3)
This is wrong, error message:
(Random.float (fps 24)) < 0.3
Expected Type: Bool
Actual Type: Signal.Signal a
The best way to debug this type of thing is to follow the types. Break every part into a separate piece, examine the types and resolve the type error.
We have a few things here:
lift : (a -> b) -> Signal a -> Signal b
asText : a -> Element
Random.float : Signal a -> Signal Float
fps : number -> Signal Time
(<) : number -> number -> Bool
Okay, so let's start plugigng in values and resolving the types:
fps 24 : Signal Time
Random.float (fps 24) : Signal Float
(Random.float (fps 24)) < 0.3 : ???
This is where our type error is coming from. We are trying to pass in a Signal but the (<) operator only accepts number. So, what we actually want is a function that compares the value in our Signal to see if it is < 0.3.
foo : Float -> Bool
foo n = n < 0.3
Now, we can lift foo and pass the signal into it:
lift foo (Random.float (fps 24))
And then plug it back into our original expression:
main = list asText (lift foo (Random.float (fps 24)))
Now, all of the types resolve.
Hope this helps!
Related
I am trying to generate a Stream value in a monadic context. For example, the following code hangs in Idris (or segfaults):
import Control.Monad.State
count : State Int (Stream Int)
count = do
x <- get
put (x+1)
t <- count
pure (x :: t)
stream : List Int
stream = take 10 (evalState count 0)
However, similar code works in Haskell, using the lazy state monad:
import Control.Monad.State.Lazy
count :: State Int [Int]
count = do
x <- get
put (x+1)
t <- count
return (x : t)
stream :: [Int]
stream = take 10 (evalState count 0)
This is probably because of lazy pattern matching used in the bind operation of the state monad in Haskell. Is there something similar in Idris?
I am trying to create a Random.Generator (Float, Float) where the first Float is in some range say 0.0 1000.0 and the second between 0.0 and the first value.
Example of valid values: (12.0, 5.0)
Invalid: (303.0, 800.0)
I looked over code in Random.Extra module but I wasn't able to find my way around.
The example bellow don't even compile. :)
tuple =
let range = float 0.0 500.0
in flatMap (\max -> (max, float 0.0 max)) range
Here is the generator code:
floatTuple : Random.Generator (Float, Float)
floatTuple =
Random.float 0.0 1000.0
`Random.andThen`
(\val1 -> Random.map ((,) val1) (Random.float 0 val1))
And here is how you can use it (in 0.17):
(tuple, nextSeed) = Random.step floatTuple initialSeed
You need to use Random.andThen
Here is a full working example (you can copy&paste it in http://elm-lang.org/try)
import Html exposing (..)
import Html.App as App
import Random exposing (Generator, generate, float, map, andThen)
import Time exposing (every, second)
myPair : Float -> Float -> Generator (Float, Float)
myPair min max =
let
range = float min max
in
range
`andThen` (\f -> map ((,) f) (float min f))
type Msg = Request | Update (Float, Float)
update msg model =
case msg of
Request -> model ! [generate Update (myPair 0 1000)]
Update pair -> pair ! []
view model = text (toString model)
main =
App.program
{ init = (0,0) ! []
, update = update
, view = view
, subscriptions = (\_ -> every (2*second) (always Request))
}
I would like to compute a random value with a multimodal distribution composed of N normal distributions.
I have an array with N elements of normal distribution parameters (std deviation, mean).
My language (VHDL) and my library allow me to calculate the following basic distributions:
- uniform distribution [-1.0; 1.0]
- normal distribution (Box Muller transformation)
- Poisson distribution
How can I calculate random values so that the histogram looks like N overlapping normal distributions?
Types and helpers:
type T_NORMAL_DIST_PARAM is record
StdDev : REAL;
Mean : REAL;
end record;
type T_JITTER_DIST is array(NATURAL range <>) of T_NORMAL_DIST_PARAM;
constant JitterDistribution : T_JITTER_DIST := (
0 => (0.2, -0.4),
1 => (0.2, 0.4)
);
The problems core:
procedure getMultiModalDistributedRandomNumber(Seed : T_SIM_SEED; Value : REAL; JitterDistribution : T_JITTER_DIST) is
variable rand : REAL;
variable Result : REAL;
begin
-- ...
for i in JitterDistribution'range loop
getNormalDistributedRandomValue(Seed, rand, JitterDistribution(i).StdDev, JitterDistribution(i).Mean);
-- how to accumulate rand?
end loop;
Value := Result;
end procedure;
It's used in:
procedure genClock(signal Clock : out STD_LOGIC; Period : TIME) is
constant TimeHigh : TIME := Period / 2;
constant TimeLow : TIME := Period - TimeHigh;
variable rand : REAL;
begin
initializeSeed(Seed);
while (not isStopped) loop
getMultiModalDistributedRandomNumber(Seed, rand, JitterDistribution);
Clock <= '1';
wait for TimeHigh + (Period * rand);
Clock <= '0';
wait for TimeLow;
end loop;
end procedure;
I'm making a game where I need to draw random lines on the screen. Now it seems like Random needs a signal to work in 0.13 (and we are forced to work in 0.13). So how do I obtain those random number?
I started from the game skeleton provided at the elm-lang website and got to this:
type UserInput = { space : Bool, keys : [KeyCode] }
type Input = { timeDelta : Float, userInput : UserInput }
userInput : Signal UserInput
userInput = lift2 UserInput Keyboard.space Keyboard.keysDown
framesPerSecond = 30
delta : Signal Float
delta = lift (\t -> t / framesPerSecond) (Time.fps framesPerSecond)
input : Signal Input
input = Signal.sampleOn delta (Signal.lift2 Input delta userInput)
gameState : Signal GameState
gameState = Signal.foldp stepGame defaultGame input
stepGame : Input -> GameState -> GameState
stepGame i g =
if g.state == Start then *Get random floats*
Now in stepGame, I want to draw random lines. The problem is that I can only get random floats by providing a signal in 0.13. I have the Input signal close by the step function, but when I change the header to lets say
stepGame : Signal Input -> GameState -> GameState it doesn't compile. So how do I get a signal in that function to get some random numbers... I can't seem to find the solution, it's driving me crazy.
There are two ways to do this. It really depends on whether the amount of random numbers you need is static or not.
Static number of random numbers
Extend your input with random numbers from Random.floatList:
type Input = { timeDelta : Float, userInput : UserInput, randoms : [Float] }
staticNoOfFloats = 42
input : Signal Input
input = Signal.sampleOn delta (Signal.lift3 Input delta userInput (Random.floatList (always staticNoOfFloats <~ delta)))
Dynamic number of random numbers
Use a community library (also outlined in this SO answer) called generator. You can use a random seed by using Random.range in much the same way as outlined above. The library is a pure pseudo-random number generator based on generating a random number and a new Generator that will produce the next random number.
Why not use Random.floatList in the dynamic case?
Usually if you need a dynamic number of random numbers that number is dependent on the current state of the program. Because that state is captured inside the foldp, where you're also doing your updating based on those random numbers, this makes it impossible to use a "signal function", i.e. something of type Signal a -> Signal b.
This code is from http://elm-lang.org/edit/examples/Intermediate/Stamps.elm. I did a minor change, see below.
import Mouse
import Window
import Random
main : Signal Element
main = lift2 scene Window.dimensions clickLocations
-- for a good time, remove "sampleOn Mouse.clicks" ;)
clickLocations : Signal [(Int,Int)]
clickLocations = foldp (::) [] (sampleOn Mouse.clicks Mouse.position)
scene : (Int,Int) -> [(Int,Int)] -> Element
scene (w,h) locs =
let p = Random.float (fps 25)
drawPentagon p (x,y) =
ngon 5 20 |> filled (hsla p 0.9 0.6 0.7)
|> move (toFloat x - toFloat w / 2, toFloat h / 2 - toFloat y)
|> rotate (toFloat x)
in layers [ collage w h (map (drawPentagon <~ p) locs) // I want to change different color each time, error here!
, plainText "Click to stamp a pentagon." ]
How can I pass a signal when using map function?
In your code, you have drawPentagon <~ p which has the type Signal ((Int, Int) -> Form)
The type of map is map : (a -> b) -> [a] -> [b] which is causing the type error. It is basically saying, that map is expecting a function a -> b but you've given it a Signal ((Int, Int) -> From).
One way to try and accomplish what you're doing is to make p a parameter of scene and use lift3 to pass in Random.float (fps 25). So, you would end up with this:
import Mouse
import Window
import Random
main : Signal Element
main = lift3 scene Window.dimensions clickLocations (Random.float (fps 25))
-- for a good time, remove "sampleOn Mouse.clicks" ;)
clickLocations : Signal [(Int,Int)]
clickLocations = foldp (::) [] (sampleOn Mouse.clicks Mouse.position)
scene : (Int,Int) -> [(Int,Int)] -> Float -> Element
scene (w,h) locs p =
let drawPentagon p (x,y) =
ngon 5 20 |> filled (hsla p 0.9 0.6 0.7)
|> move (toFloat x - toFloat w / 2, toFloat h / 2 - toFloat y)
|> rotate (toFloat x)
in layers [ collage w h (map (drawPentagon p) locs)
, plainText "Click to stamp a pentagon." ]
Is this what you were trying to do?