// leaving old Box for comparison
const Box = x => ({
    map: f => Box(f(x)),
    fold: f => f(x),
    inspect: _ => `Box(${x})`,
})

// wraps a function returning value without executing its call
const LazyBox = g => ({

  // compose with f from outside
  map: f => LazyBox( _ => f(g()) ),

  // compose and evaluate
  fold: f => f(g())
})


const nextCharForNumberString = str =>

  // wrap 'str' first into function call
  LazyBox( () => str )

  // every 'map' composes with new function from outside
  // without calling it
  .map(s => s.trim())
  .map(r => parseInt(r))
  .map(i => i + 1)
  .map(i => String.fromCharCode(i))

  // compose again and call the function
  .fold(s => s.toLowerCase())

console.log(nextCharForNumberString(' 64 '))


// ==== Experiment

// The bove LazyBox needs a function and ignores its arguments.
// It must be called every time as LazyBox( () => val ),
// which may not be convenient to consume
// It may be more convenient to pass the actual value:


// TODO === not finished yet

const LazyWrapper = x => ({

  wrapper: () => x,

  // compose with f from outside
  map: f => LazyWrapper( f(x) ),

  // compose and evaluate
  fold: f => f(x)
})

const nextCharForNumberString1 = str =>

  // wrap 'str' first into function call
  LazyWrapper( str )

  // every 'map' composes with new function from outside
  // without calling it
  .map(s => s.trim())
  .map(r => parseInt(r))
  .map(i => i + 1)
  .map(i => String.fromCharCode(i))

  // compose again and call the function
  .fold(s => s.toLowerCase())

console.log(nextCharForNumberString1(' 64 '))



@@ -303,33 +303,44 @@
 ose and evaluate
+ only here!
 %0A
-
   fold: f =%3E f(g
@@ -444,855 +444,12 @@
 ox( 
-() =%3E str )%0A%0A  // every 'map' composes with new function from outside%0A  // without calling it%0A  .map(s =%3E s.trim())%0A  .map(r =%3E parseInt(r))%0A  .map(i =%3E i + 1)%0A  .map(i =%3E String.fromCharCode(i))%0A%0A  // compose again and call the function%0A  .fold(s =%3E s.toLowerCase())%0A%0Aconsole.log(nextCharForNumberString(' 64 '))%0A%0A%0A// ==== Experiment%0A%0A// The bove LazyBox needs a function and ignores its arguments.%0A// It must be called every time as LazyBox( () =%3E val ),%0A// which may not be convenient to consume%0A// It may be more convenient to pass the actual value:%0A%0A%0A// TODO === not finished yet%0A%0Aconst LazyWrapper = x =%3E (%7B%0A%0A  wrapper: () =%3E x,%0A%0A  // compose with f from outside%0A  map: f =%3E LazyWrapper( f(x) ),%0A%0A  // compose and evaluate%0A  fold: f =%3E f(x)%0A%7D)%0A%0Aconst nextCharForNumberString1 = str =%3E%0A%0A  // wrap 'str' first into function call%0A  LazyWrapper(
+_ =%3E
  str
@@ -720,16 +720,20 @@
 ole.log(
+%0A  %22
 nextChar
@@ -751,17 +751,16 @@
 ring
-1
 (' 64 ')
 )%0A%0A%0A
@@ -755,12 +755,50 @@
 (' 64 ')
+: %22,%0A  nextCharForNumberString(' 64 '
 )%0A
+)
 %0A%0A

Update lazy box