This is more of a theoretical question but I feel like there must be a way to do this.
I have JS components for which, when they are created, they need to assign a unique id to an html element, one that hasn't been used in any other component. This is pretty trivial normally:
let currentId = 0;
function getNextId() {
currentId += 1;
return currentId;
}
function MyComponent() {
this.id = getNextId();
// Code which uses id
}
let c1 = new MyComponent();
// c1.id === 1
let c2 = new MyComponent();
// c2.id === 2
I'm wondering if there's any way to do this kind of thing using just pure functions, as I'm trying to wrap my head around some more advanced pure functional ideas. As far as I can tell it would require Monads or something of that variety to accomplish, but I don't know how to do so.
Thank you!
In Haskell, you might write something like
import Control.Monad.State
data Component = Component Int String deriving (Show)
getNextId :: State Int Int
getNextId = do x <- get
put (x + 1)
return x
makeComponent :: String -> State Int Component
makeComponent name = do x <- getNextId
return (Component x name)
components = evalState (traverse makeComponent ["alice", "bob"]) 0
main = print $ components
The above script would output
[Component 0 "alice",Component 1 "bob"]
as each "call" to getNextId
would "return" the next number in line. The traverse
function is something like map
, but it ensures that the effect of each monad takes place during the course of applying makeComponent
to each value.
This link may provide some assistance in adapting this to Javascript.
The State
type constructor itself is just a wrapper around a function, here of type Int -> (Int, Int)
. The Monad
instance for this type lets you avoid writing code that looks like this:
getNextID :: Int -> (Int, Int)
getNextID x = (x, x+1)
makeComponent :: String -> Int -> (Int, Int)
makeComponent name x = let (now, then) = getNextID x
in (then, Component now name)
components = let state_0 = 0
(state_1, c1) = makeComponent "alice" state_0
(state_2, c2) = makeComponent "bob" state_1
in [c1, c2]