[Question]
  [
Write a program or function (hereafter "function") that returns or prints the source code of four new functions: Increment, decrement, undo, and peek.
The initial function contains an internal integer value of `0`. Each of the returned functions contains a value based on that value, and each behaves differently:
* **Increment** contains the value of the function that created it plus 1. When called, it returns or prints the source code of four new functions: Increment, decrement, undo, and peek.
* **Decrement** contains the value of the function that created it minus 1. When called, it returns or prints the source code of four new functions: Increment, decrement, undo, and peek.
* **Undo** returns increment, decrement, undo, and peek functions equivalent to those returned by the function that created the function that created it, i.e. its grandparent. Calling successive Undo functions will return functions earlier and earlier in the "history." *Note: Because the very first generation of Undo has no "grandparent" its behavior is undefined. It may return any value, throw an error, etc.*
* **Peek** contains the value of the function that created it. When called it returns or prints that value.
## Example
Suppose `yourFunction` is your initial function. It returns four strings that contain the source code of the subsequent functions.
```
[incr, decr, undo, peek] = yourFunction();
eval(peek)(); // => 0
[incrB, decrB, undoB, peekB] = eval(incr)();
eval(peekB)(); // => 1
[incrC, decrC, undoC, peekC] = eval(incrB)();
eval(peekC)(); // => 2
[incrD, decrD, undoD, peekD] = eval(incrC)();
eval(peekD)(); // => 3
[incrE, decrE, undoE, peekE] = eval(undoD)();
eval(peekE)(); // => 2
[incrF, decrF, undoF, peekF] = eval(undoE)();
eval(peekF)(); // => 1
[incrG, decrG, undoG, peekG] = eval(decrF)();
eval(peekG)(); // => 0
eval(peekF)(); // => 1
```
## Rules
1. This is a [code-generation](/questions/tagged/code-generation "show questions tagged 'code-generation'") challenge. With the exception of "peek," the initial function and the functions it creates (and the functions they create and so on) must return source code that can be stored (copied/pasted, saved in a file, et al) and executed in a separate session. Returning a closure, for example, is not valid.
2. The functions generated don't need to be named "increment," "decrement," etc. They're not required to be named at all.
3. The "depth" of the Undo functions, i.e. how far back you can go in their "history," should be limited only by memory or language constraints.
4. You're encouraged to include in your answer examples of the four functions generated by your initial function or its successors.
5. The output formats are flexible. Inclusive of rule (1), [standard I/O rules](https://codegolf.meta.stackexchange.com/questions/2447/default-for-code-golf-input-output-methods/) apply; your initial function—and the subsequent functions—could return four programs separated by newlines; an array of four strings; an object with four string properties; four files; etc.
6. [Standard rules](https://codegolf.meta.stackexchange.com/questions/2419/default-for-code-golf-program-function-or-snippet/2422#2422) apply and [standard loopholes](https://codegolf.meta.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default) are forbidden.
7. This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"). Your score is the number of bytes in your initial function. Lowest number of bytes wins.
  
[Answer]
# [Wolfram Language (Mathematica)](https://www.wolfram.com/wolframscript/), ~~54~~ 35 bytes
```
Hold[1~#0~##,#0[-1,##],#0@##2,+##]&
```
[Try it online!](https://tio.run/##TY5Ra4MwFIWfk18hCZQNleke21myWt0GKxvsMYSRaqRhMUqNg620f92ZWTBP9/Cdc7in5uYgam5kwYcqGZ4bVdL4gqMLxgGOaBgHGLNREYzvA3/Ui@Gtqmje68LIRi@XnWpMx@CuKXsl6EnqIonOAQSdES3VvBafzFsm3s1o@P4KApB9c9VzI@jHT71vFMUP65eKjvY6HmsApLyVhiv5K8ijag98Lwxl1AYYCxBibGFTd@SERnREgYdKMd1el429rRBf6My8xHuVnSHEroDgFjJoR5GKXoXte6v3o9SG2M5mxhsHpzNOHbydsH26dXA248zB@YTt1NzBT9CNTBqFYYiu@v/p8Ac "Wolfram Language (Mathematica) – Try It Online")
Returns `Hold[incr, decr, undo, peek]`, where the expression body consists of four unevaluated expressions. When evaluated, `incr`, `decr`, and `undo` reduce to similar four-element `Hold[...]` expressions, and `peek` to an integer\*.
\* Upon `undo`ing with no history, `peek` takes on the value `##2`, and subsequent `incr`/`decr` operations yield `peek=n+##2` for some integer `n`. `undo`ing that `undo` restores `peek=0`.
[Answer]
# JavaScript (ES6), 98 bytes
```
f=(k=0,p='' )=>[(g=n=>(0+f).replace(/\S*/,`f=(k=${k+n},p="${btoa(f)}"`))(1),g(-1),atob(p),"_=>"+k]
```
[Try it online!](https://tio.run/##jdHPb4IwFAfwO39FQ0xoB4Juyy6mJPLztotHNROxJQijBNBkMf7trPCMk0SSXWhC3/u8b9tjdI7quErLZlqIA2stC5Ui/@FpnteIiwp9yr/msVb2jYgQRTWiNnJOnLPK5JX4xjXSkaYRsxGrpkqLBGv7qGYf7xpZKFEj9uM9BrqX/nXLLiWgLac4ozOjpJqGCLXXOKEFtfFM58SsWJlHMcPWZvViGbu@dHLJ9OIq69XJpUuKObmqO0LwnBgJnspvlwWXxFC/qK3q2bZdKOu0iKulgQ6sX07FQcilZCxbbmXsoAsTi6IWOTNzkWB2jnLcbxNMyALJu5IHmykAOQA5ADkAOR3U9/WzyCjpPJLzG@kC6QLpAukOSGecdB/J1xvpAekB6QHpDUh3nPQeybcb6QPpA@kD6d/Jfs446T9LGQAZABkAGQxIf5wMnt1lCGQIZAhkeCf7ceNkOHzxf4xtfwE "JavaScript (Node.js) – Try It Online")
[Answer]
# [Rust](https://www.rust-lang.org), 603 bytes
```
fn f(){let m=("fn ","(){let m=",";let n=vec!",";println!(\"fn a(){{println!(\\\"","\\\")}}\");for i in [(\"b\",",",\"\"),(\"c\",",",\"\"),(\"d\",",",\"o.pop();\")]{let mut o=n.clone();o.push(i.1);","println!(\"{}{}{}{:?}{}{:?}{}{}{}{}{}{}{}{}{}{}{}\",m.0,i.0,m.1,m,m.2,o,m.3,i.1,m.4,i.1+1,m.5,i.1-1,m.6,o[o.len()-2],m.7,i.2,m.8);}}");let n=vec![0,0];println!("fn a(){{println!(\"0\")}}");for i in [("b",1,""),("c",-1,""),("d",0,"o.pop();")]{let mut o=n.clone();o.push(i.1);println!("{}{}{}{:?}{}{:?}{}{}{}{}{}{}{}{}{}{}{}",m.0,i.0,m.1,m,m.2,o,m.3,i.1,m.4,i.1+1,m.5,i.1-1,m.6,o[o.len()-2],m.7,i.2,m.8);}}
```
[Attempt This Online!](https://ato.pxeger.com/run?1=rVJLboMwFJS6a07hvJWtGgvoLypCPQiwSAiolsBGBLpBnKSbLNoT9DY9TcdJE5oqiyyqJ95nZpDt0Xt7b_tNt91-9F3pLb6uktKwkouhKjpWx5wwkqQjgD5ynYlfi3zupqbVpqvMnKdOu4RymKA0JWhcEeOIFJW2ZZppwxLoVylIREqgJID8L7A-AlY1tuEiApHt79J3zMZG5ZU1BQgI-s0L1yoQEX75da1h3MXT85TPBE6qlS81vloFskYOpUW-BYZZ3bl647p713mue5A2saoqDBdemAF4BBWiLkQ0jnjv5FXiSz-b3DpjFvk7m05dohXJQJKzg3KS3qFfk_Tl0ZVLTJmOvsyQ__djv2OfeHm91JCwYXaNXYtmP8xhC78B)
[Attempt this after a couple iterations](https://ato.pxeger.com/run?1=7VXdTsIwFL408hTlXLWxLKygEhbig1AuWDfikq0lsHmz9Em88UIfSp_G0w0oBoxcGKORdTs95_v6ty9f0sfnVbUun55eqnLRG71dpAtN5pTVy1Wmy1x3KQhgtoNojGielqSYUMASOIEd4orIpXrykKpuU-5WkLBZ0y8qpQQ3yPXMWgzRwqxIRjJNpjghlsAdzyUgxxFRB0jiERMszZKyCJlZe6KqJGaiA5UbnSKBA6r1Pc2CkEVuzt7Zatu08Z2PRxruVQR9nuFXBCEvMApuMA4QwzoYuv7KZdcu67nshpupCfJUU9YTMwRukRLYj1hkLf6zV2za5wTfkBPByWDmxTuiHQwa0T5qBjHwIQcnDSjgYpMmTbrV5xR5_M6nKfP9wjizqbPZfshs4RdmCz8xm_Bm6_9xsyVns_0Hs23H_gLTtbfta40SFPMMB5G6Q_DxR5uPUYXOJQqE0cNSxy0RHxCqIdwqim6SfTrZ0YmjbXuE7cX_Dg)
Probably not anywhere close to optimally golfed, but I'm pretty impressed with myself for getting it to work at all.
Expanded version:
```
fn f() {
    let m=("fn ","(){let m=",";let n=vec!",";println!(\"fn a(){{println!(\\\"","\\\")}}\");for i in [(\"b\",",",\"\"),(\"c\",",",\"\"),(\"d\",",",\"o.pop();\")]{let mut o=n.clone();o.push(i.1);","println!(\"{}{}{}{:?}{}{:?}{}{}{}{}{}{}{}{}{}{}{}\",m.0,i.0,m.1,m,m.2,o,m.3,i.1,m.4,i.1+1,m.5,i.1-1,m.6,o[o.len()-2],m.7,i.2,m.8);}}");
    let n = vec![0, 0];
    println!("fn a(){{println!(\"0\")}}");
    for i in [("b", 1, ""), ("c", -1, ""), ("d", 0, "o.pop();")] {
        let mut o = n.clone();
        o.push(i.1);
        println!(
            "{}{}{}{:?}{}{:?}{}{}{}{}{}{}{}{}{}{}{}",
            m.0,
            i.0,
            m.1,
            m,
            m.2,
            o,
            m.3,
            i.1,
            m.4,
            i.1 + 1,
            m.5,
            i.1 - 1,
            m.6,
            o[o.len() - 2],
            m.7,
            i.2,
            m.8
        );
    }
}
```
[Answer]
# [Rust](https://www.rust-lang.org), 279 bytes
```
||{macro_rules!q{($x:tt)=>{$x(stringify!($x))}}
q!((|s|move|mut v:Vec<_>,n|{let f=|m,u:&_|format!("||{{macro_rules!q{{($x:tt)=>{{$x(stringify!($x))}}}}
q!({})(vec!{:?},{})}}",s,u,m);v.push(n);(f(n+1,&v),f(n-1,&v),f({v.pop();v.pop()}.unwrap(),&v),format!("||{}",n))}))(vec![0],0)}
```
This is a nullary closure that returns a 4-tuple of strings. It uses a macro to do most of the quine heavy-lifting. The state is inserted right towards the end, using a vector for the undo history. The undo history starts with a single entry so the `.unwrap()` doesn't panic, but the program outputted using it *will* panic.
[Attempt This Online!](https://ato.pxeger.com/run?1=bZBBTsMwEEXFNhdg60RVZYtpVXYooeUWbCgKIbEhop6kiR2KbJ-ETRaw5zpwGtymhQqxmv9HX_-N_frW6Fb1HwKJzEqkzKy4ImL-rpWYXHydnFprZJY3VdroFW_DtaGjTawUmy_MaENb1ZT4UIqX0K8Zcy5Yh5Ta1sqq41ZqRbr4mueX6QLQ7qutBB2PUyuqRmYqpJFH_GEcQf6lDBzjGO14Hpr4yoE3zkXQggbJkm5a6_aRIkuooHh2DuOOgVeTgzI-UdV0l9xON9X43GReDYGj23wreigbYDezW5gxN_zP510SELJ9Fs3gHnIoGJkT4Wv9uvZHqxX6khLzeInGLXGJBf_VGovqx9ScP-1MBIeuJNhz-n6Y3w) ([after a few iterations](https://ato.pxeger.com/run?1=bVDBTsMwDBXXfoVbTSgR2QScUMfGX3BhaJQuGRWr27VJGUrzJVx2gDu_A1-D0xaYEFEk-1nPfs9-ea1MrffvCiFPMmTcbqQGNXszWo0vPo_WbWvzJK2KZWU2sg63lo12sdZ8NrejHat1leE6U88hlTl3LtiGjLVQQwt50UgfjIYGYriWKVzCEuYCENrABkCvE4OZpwkwxDomRguqqPJEhx2FRWThj4cDE_-66H1Yx1kj09DGV04QcC4S3ciatATkHKbQTEpTPzCkvFdTDOEEzgQ5abgAD8eH0PqWomRDc5e5icGnKqF04HWjhiX6BUgakPPA8d7TzakA-jT4_Faccdff--POu_BHYYm4F6lYcTqOYtyXS1pSbzBkUYZpvEDrFrjAlfzNDa6KH1BK-diBSHzPmgaDzn7fxy8))
Initial output:
```
// inc
||{macro_rules!q{($x:tt)=>{$x(stringify!($x))}}
q!((| s | move | mut v : Vec < _ >, n |
{
    let f = | m, u : & _ | format!
    ("||{{macro_rules!q{{($x:tt)=>{{$x(stringify!($x))}}}}
q!({})(vec!{:?},{})}}",
    s, u, m) ; v.push(n) ;
    (f(n + 1, & v), f(n - 1, & v), f({ v.pop() ; v.pop() }.unwrap(), & v),
    format! ("||{}", n))
}))(vec![0, 0],1)}
// dec
||{macro_rules!q{($x:tt)=>{$x(stringify!($x))}}
q!((| s | move | mut v : Vec < _ >, n |
{
    let f = | m, u : & _ | format!
    ("||{{macro_rules!q{{($x:tt)=>{{$x(stringify!($x))}}}}
q!({})(vec!{:?},{})}}",
    s, u, m) ; v.push(n) ;
    (f(n + 1, & v), f(n - 1, & v), f({ v.pop() ; v.pop() }.unwrap(), & v),
    format! ("||{}", n))
}))(vec![0, 0],-1)}
// undo (will panic)
||{macro_rules!q{($x:tt)=>{$x(stringify!($x))}}
q!((| s | move | mut v : Vec < _ >, n |
{
    let f = | m, u : & _ | format!
    ("||{{macro_rules!q{{($x:tt)=>{{$x(stringify!($x))}}}}
q!({})(vec!{:?},{})}}",
    s, u, m) ; v.push(n) ;
    (f(n + 1, & v), f(n - 1, & v), f({ v.pop() ; v.pop() }.unwrap(), & v),
    format! ("||{}", n))
}))(vec![],0)}
// peek
||0
```
[Answer]
# [Python REPL](https://www.python.org), ~~67~~ ~~61~~ 59 bytes
```
eval(s:='0,(n:="eval(s:=%r)")%("-~"+s),n%("~-"+s),n%s[2:]')
```
[Attempt This Online!](https://ato.pxeger.com/run?1=VdHLaoNAFAZgsvUpRAg6RKF0VSxu5voQaRelUSINo3gJBEJeJBs35p3ap6n6j3CymXOG-b9zFnN_1JfuWNlhLPzM_xj7rkjeft_z89cpatMsfIkjm2bBet82LGDbKEhuwa5lsZ3aW-Ladv-afoYMI_421zrPf2K_tN9N7B_y-eztoZq2FF7dlLaL5gDzvLlwBDmSHFE-ZZfF8xMjiDsloASUgBJUccqEYxJMgkkwSZmgTDqmwBSYAlMrW2ZQphzTYBpMg2nKFGXaMQNmwAyYWdkyijLzPAOfMAyo_w)
Outputs `(peek, incr, decr, undo)`
# [Python](https://www.python.org), ~~89~~ ~~99~~ ~~93~~ ~~91~~ 86 bytes
```
lambda:eval(s:='(n:="lambda:eval(s:=%r)")%(s+"\'+1\'"),n%(s+"\'-1\'"),n%s[:-4],n%"0"')
```
[Attempt This Online!](https://ato.pxeger.com/run?1=bdFPaoQwHIZhuvUUEhhMGIUWuiiCm_wxN-imdmGr0qEzGVFnoGfpxs30ML1Be5pqvkqkzUb9hbxPAr5_tG_Dy9GMlybMwuJyGprk7ut-Xx6eqjKtz-We9mkWUZNm5M_ipmOEbWi_JUW0vSkiwmLzOybL2D-kye3j9EGuScSgf1997sxzF4dVPT9PpjrGYVvXr9MFGsqCttuZgdpT5lVGGQuCueBIOBqOiE-V3TvvYP9z7nqBXqAX6MW65x5AOEACkAAkALkGhAeQDlAAFAAFQC2ART2AckAOIAeQA8jXgPIAuQM0AA1AA9ALYG0PoC3gU_FLxxHvHw)
Outputs `(incr, decr, undo, peek)`
+10 bytes due to an oversight (peek was a lambda and not a string which contained a lambda. [Old Answer](https://ato.pxeger.com/run?1=XdFNTsMwEAVgsc0pQjb1qAkCVihSNv49AwIWgSSionWiNEVCiIvAJptyJzgNdV5rxWzs0eh945H89d29Dc-tHfdNXMT3-93QZDc_t-ty81iVef1artk2LxbM5kXyr_l-3n9QctG0_aYciG2XyfIqodS6KjtWd3l2_UDpUV4uCA_8nn2u7FOfxlXtzp2t2jTu6vrlsEPDKOr6lR2YazCiKHJZjjBHmiPOD_lpHZegAHIvBaSAFJBiLnlIhacSVIJKUDmnIqTSUwWqQBWoOtFpXEiVpxpUg2pQPacqpNpTA2pADag50WlqSI2j4SR80Tji_gM))
[Answer]
# [Kotlin 1.7.10](https://kotlinlang.org/), 494 490 bytes
```
{val q='!'+1;val h=listOf(0,0);fun p(h:List<Int>){val l=listOf("{val q='!'+1;val h=listOf(","h.joinToString()",");fun p(h:List<Int>){val l=listOf(",");print(l[0]+h.joinToString()+l[2]);for(r in l)print(q+r+q+',');println(l[3])};p(h+(h.last()+1));p(h+(h.last()-1));p(h.dropLast(1));print('{');print(h.last());print('}')}");print(l[0]+h.joinToString()+l[2]);for(r in l)print(q+r+q+',');println(l[3])};p(h+(h.last()+1));p(h+(h.last()-1));p(h.dropLast(1));print('{');print(h.last());print('}')}
```
[Try it on Kotlin Playground!](https://play.kotlinlang.org/#eyJ2ZXJzaW9uIjoiMS43LjIwIiwicGxhdGZvcm0iOiJqYXZhIiwiYXJncyI6IiIsIm5vbmVNYXJrZXJzIjp0cnVlLCJ0aGVtZSI6ImlkZWEiLCJjb2RlIjoidmFsIGZ1bmN0aW9uID0ge3ZhbCBxPSchJysxO3ZhbCBoPWxpc3RPZigwLDApO2Z1biBwKGg6TGlzdDxJbnQ+KXt2YWwgbD1saXN0T2YoXCJ7dmFsIHE9JyEnKzE7dmFsIGg9bGlzdE9mKFwiLFwiaC5qb2luVG9TdHJpbmcoKVwiLFwiKTtmdW4gcChoOkxpc3Q8SW50Pil7dmFsIGw9bGlzdE9mKFwiLFwiKTtwcmludChsWzBdK2guam9pblRvU3RyaW5nKCkrbFsyXSk7Zm9yKHIgaW4gbClwcmludChxK3IrcSsnLCcpO3ByaW50bG4obFszXSl9O3AoaCsoaC5sYXN0KCkrMSkpO3AoaCsoaC5sYXN0KCktMSkpO3AoaC5kcm9wTGFzdCgxKSk7cHJpbnQoJ3snKTtwcmludChoLmxhc3QoKSk7cHJpbnQoJ30nKX1cIik7cHJpbnQobFswXStoLmpvaW5Ub1N0cmluZygpK2xbMl0pO2ZvcihyIGluIGwpcHJpbnQocStyK3ErJywnKTtwcmludGxuKGxbM10pfTtwKGgrKGgubGFzdCgpKzEpKTtwKGgrKGgubGFzdCgpLTEpKTtwKGguZHJvcExhc3QoMSkpO3ByaW50KCd7Jyk7cHJpbnQoaC5sYXN0KCkpO3ByaW50KCd9Jyl9XG4vLyBDYWxsIHRoZSBzb2x1dGlvbjpcbmZ1biBtYWluKCkgPSBmdW5jdGlvbigpIn0=)
A function/lambda that prints the source code for four new lambdas: increment, decrement, undo and peek.
Calling the first-generation undo function produces a lambda that compiles but produces invalid sources for its own undo.
## Explanation
```
{                         // A lambda of type () -> Unit
    val q = '!' + 1       // The " character to avoid backslashes
    val h = listOf(0, 0)  // The history of numbers, initialised with two numbers
                          // to make initial undo compilable
    fun p(h: List<Int>) { // Define a nested function p(h) that prints
                          // the source code for increment/decrement/undo
        val l = listOf(   // List of source code lines to print
            "{val q='!'+1;val h=listOf(",
            "h.joinToString()",
            ");fun p(h:List<Int>){val l=listOf(",
            ");print(l[0]+h.joinToString()+l[2]);for(r in l)print(q+r+q+',');println(l[3])};p(h+(h.last()+1));p(h+(h.last()-1));p(h.dropLast(1));print('{');print(h.last());print('}')}"
        )
        print(l[0] + h.joinToString() + l[2])
        for (r in l) print(q + r + q + ',') // Print a quoted version of the whole lambda
        println(l[3])
    }
    p(h + (h.last() + 1)) // Increment
    p(h + (h.last() - 1)) // Decrement
    p(h.dropLast(1))      // Undo
    print('{')            // Peek
    print(h.last())
    print('}')
}
```
* Increment/decrement/undo are similar lambdas with a different `h`istory
* Peek is a lambda that always *returns* the last value of `h` (while the others print)
## Example outputs
After one round of incrementing:
* Increment/decrement/undo print the following program:
```
{val q='!'+1;val h=LIST;fun p(h:List<Int>){val l=listOf("{val q='!'+1;val h=listOf(","h.joinToString()",");fun p(h:List<Int>){val l=listOf(",");print(l[0]+h.joinToString()+l[2]);for(r in l)print(q+r+q+',');println(l[3])};p(h+(h.last()+1));p(h+(h.last()-1));p(h.dropLast(1));print('{');print(h.last());print('}')}",);print(l[0]+h.joinToString()+l[2]);for(r in l)print(q+r+q+',');println(l[3])};p(h+(h.last()+1));p(h+(h.last()-1));p(h.dropLast(1));print('{');print(h.last());print('}')}
```
where `LIST` is actually:
	+ Increment: `listOf(0, 0, 1, 2)`
	+ Decrement: `listOf(0, 0, 1, 0)`
	+ Undo: `listOf(0, 0)` (the original history)
* Peek prints `{1}`, a constant lambda returning the latest value in the history
-4 bytes by replacing the last `println` with `print`
[Answer]
# [JavaScript (Node.js)](https://nodejs.org), ~~64~~ 62 bytes
```
f=_=>`f=${f}+'+1'\nf=${f}+'-1'\nf=${(f+"").slice(0,-5)}\n_=>0`
```
[Try it online!](https://tio.run/##jdJRa4MwEAfwdz9FkEETrK3d2JOk0MTEDzHHKhqHmyRSu76MfnbncrYo9SFPx0H@vzuOfOWXvCtOdXsOtSlVL2lf0Q@6P1b06be6Bqtgt8r0rQlvDa4C3yebrqkLhaN1@EqumR5i0bGPvbdaF6fDGpXKlh9dmqG0Sn0f3hFFEg/BtqnP2M@0T2KvMLozjdo05hOrS95g@5RgQmK03SK6R5EHKAOUAcoAZf@ozdm5xIlnU3438hx4DjwHns945sbzKf888gnwCfAJ8MmM5258MuVfRl4AL4AXwIs7b2e68WJpewm8BF4CL2e8cOPl0u1T4FPgU@DTO29HP/DLfjr/Og479H8 "JavaScript (Node.js) – Try It Online")
-2 bytes thanks to [@emanresu A](https://codegolf.stackexchange.com/users/100664/emanresu-a)
[Answer]
# [Python 3](https://docs.python.org/3/), ~~105~~ ~~93~~ 83 bytes
-12 bytes thanks to 97.100.97.109   
-10 bytes thanks to Mukundan314 and xnor
```
print(*map(open(__file__).read().replace,['0']*3,['-~0','~-0','0'[2:]]),'print(0)')
```
Outputs [incr, decr, undo, peek] separated by spaces
[Try it online!](https://tio.run/##bdDdboMgFAfwe5@CeAM01Jj1rslu/HyIpjFOcXNlQBTTLsv66k48dB8dXEBAzu9/UL@bFyV3c6Najh5RGIazHnppyOat1kRpLklVdb3gVUWjgdctsYsWdcPZAcf4uNkt6/YaY4avWzvH@PCwPx4pwwDFFNN5caPRDL0mNAha3iF@4U2lJqMnQ2w23QdoGZ1emviTyhA@Y@o@RuehNxwKbkeNUCO3rN2DuD5k3duorj7xyj3q4nLskEoK1dTCFX2f/xgojF5VL8kFwmzPazZDH5vNs1BPtRgJZShc9XD/K@oTSgZupkHeEoJeNgNbmrLzJFvFkOb8tET9@x3RqEVvlmetofYWhfIE6hMAEhCSO8Je9BCJM1IwUjBSMFKPkXiQ1CEZIBkgGSCZB0k9SOaQHJAckByQ/A5ZfQ@SO6QApACkAKTwILkHKRxSAlICUgJS3iFrjAcp/4DzFw)
[Answer]
# [Bash](https://www.gnu.org/software/bash/), ~~68~~ 51 bytes
```
echo 'bc<<<0';sed 's/0/0+1/p;s/+/-/p;s/0..../0/' $0
```
[Try it online!](https://tio.run/##Zc/NisIwEAfwe55ikEIUiUm6R8NCPz3uI0ibBhTdWprWi/js3TBzqZu5BP6/ZDLTNv6y2GaCb7DzOIIxvPqp@eLs5QG8tcYYxY/edcC9VFLttRyOXu6lwFMdQoWcQ6KW8JBN49yHdg6EB6GxJ2N@uF@nc5DtDl4MQmECogPRaBB3DWbbhkkg0TtIUrzy@4RN8krfahOS8@Dc7SPWGF97O37EKcad@xd/YTz33YO9V/PQzhnDvzP6ZKUZ9oecPI88Jy/Ii8gL8pK8jLzEiaAiryKvyGvyOvIaF4UT@Yl8dXf5Aw "Bash – Try It Online")
-17 bytes thanks to [@Jiří](https://codegolf.stackexchange.com/users/101306/ji%c5%99%c3%ad)
Outputs `[peek, incr, decr, undo]` seperated by newlines
[Answer]
# [C (gcc)](https://gcc.gnu.org/), 241 bytes
```
// 0
v;f;l;char*e,b[999];c(n){f=fopen(__FILE__,"r");for(l=1;fgets(b,999,f);l=0)l?v=strtol(b+3,&e,10),printf(n-80?n-85?"// %d%s":"// %s%s":"%s",n-80?n-85?n-73?v-1:v+1:"":b,n-85?b+2:e):puts(b);}main(){c(73);c(68);c(80);c(85);printf("%d\n",v);}
```
[Try it online!](https://tio.run/##RY7BSsQwFEX3foUEKol9YVLLOG1C6UpB8A9USpNJ6kBMS1LjYvDXjZkiuDlcHvdynqKTUintdtfsKgojrFDvo7/VIF/atn0TCjtyNp2ZF@3wMDw@PT8MAyCPiDCzx7arhJn0GrCE3AdDhO0YsX3swurX2WJZ1nCjoWIEFn9yq8GONqzP2Pcoa4tjERDfUthSBvxXHD3UfaQVj2XFEeIStrMs77gmfPm8mIn4/hhPDpOzwoea5J/vmwsbtnFPxJ8ZFcdXhyDmQUo/ythxCol@/QI "C (gcc) – Try It Online")
~~Creates~~ Prints the source code the following programs:
* `I` increment
* `D` decrement
* `P` peek
* `U` undo
[Full Example](https://tio.run/##fVFRT8IwEH7fr2hqMC10MCQKrs69qAmJiT7okxoCXQcNpV3WMTTGv@68VYw8GG/Ll2931919X0W4FKJpBgMUBUfKCL3NJLpwVaZsf3UZWK54zdd88XQO8cLFal52NetK1i14IIih764olalysmC4I/qvmBnKbZLbQhoym91Mb69nM4ZLTLnaZ6FzB5@5Lck6GfJ8KSsHyXYCs5Svk4iuU53oVMeuKrNtQRaU1QnwymqieyN2LNkwoizfj1bMhJMoBThNMUjpZB2HY8@cZwAHLSYcj9I6HMZ1bxhjHGvm07p3Eksa58XWr6NgQ6Gtk@SXwXYHcjc1ahW3IDjY6AkKdyi0QGHi9wNn3lwlN6CCfwSbuTKEvgsyHlEuyNmkxUnk8ZTy/d9xJ3s2mKGa8iBAEKClWimH4LVGvyEwD2VyYw24Mq@UWSJl0MP0zjerHJEfVxGYitr7NJT6Yhu/CwXBR9P0B1cc7eG@hekf4KuP/8OnyPV86Zpw9wU)
It is oddly satisfying running this on a machine with a spinning hdd with caching disabled.
[Answer]
# ARM Thumb machine code, 63 bytes
(Note: offset starts at 2 for alignment)
```
00000002: 0f a3 01 22 00 21 10 e0 0d a3 1a 78 98 5c 70 47  ...".!.....x.\pG
00000012: 0b a3 1a 78 01 3a 99 5c 07 e0 01 24 00 e0 ff 24  ...x.:.\...$...$
00000022: 07 a3 1a 78 99 5c 21 44 01 32 36 25 5b 1b ae 18  ...x.\!D.26%[...
00000032: 81 55 01 3e 99 5d 81 55 fb d1 42 55 70 47 01     .U.>.].U..BUpG.
```
Commented assembly
```
    .syntax unified
    .arch armv7ve
    .thumb
    .globl PEEK, INCR, DECR, UNDO
    .p2align 2,0
    // force 4 byte misalignment. Unscored.
    nop
    .globl func
    .thumb_func
    // Input: r0: pointer to output buffer, bits[1:0] = 0b10
    // Output: written to *r0
    // Clobbers: r0-r6
func:
    // Get address of data (as main code expects)
    adr    r3, data
    // Initial length
    movs   r2, #1
    // Initial value
    movs   r1, #0
    // Output the code
    b      .Lwrite_no_len
begin:
    // Input: none
    // Output: r0
    // Clobbers: r0, r2, r3
peek:
    // Get address of data
    adr    r3, data
    // Load length
    ldrb   r2, [r3, #0]
    // Load data[length]
    ldrb   r0, [r3, r2]
    // Return
    bx     lr
    // Input: r0: pointer to output buffer, bits[1:0] = 0b10
    // Output: written to *r0
    // Clobbers: r0-r6
undo:
    // Get address of data
    adr    r3, data
    // Load length
    ldrb   r2, [r3, #0]
    // Decrement length
    subs   r2, #1
    // Load new value
    ldrb   r1, [r3, r2]
    // Output the code
    b      .Lwrite_no_len
    // Input: r0: pointer to output buffer, bits[1:0] = 0b10
    // Output: written to *r0
    // Clobbers: r0-r6
incr:
    // Value to add
    movs   r4, #1
    // Jump to the common code for incr and decr
    b      .Lnext
    // Input: r0: pointer to output buffer, bits[1:0] = 0b10
    // Output: written to *r0
    // Clobbers: r0-r6
decr:
    // Value to add (I use 8-bit arith so 0xFF == -1)
    movs   r4, #0xFF
.Lnext:
    // Get address of length
    adr    r3, data
    // Load length
    ldrb   r2, [r3]
    // Load data[length]
    ldrb   r1, [r3, r2]
    // Add either 1 or 0xFF to the value
    add    r1, r4
    // Increment length
    adds   r2, #1
    // func and undo jump here to skip length calc
    // expected state:
    //   - r0 = out pointer
    //   - r1 = value
    //   - r2 = length
    //   - r3 = address of length
.Lwrite_no_len:
    // FIXME: awkward
    // Offset from beginning to data
    // Save in a register for later
    // Doesn't work in Clang
    movs.n r5, #data - begin
    // Subtract from pointer to get the beginning
    subs   r3, r3, r5
    // Add to length
    adds   r6, r5, r2
    // Store new value at the end of the stack
    strb   r1, [r0, r6]
    // memcpy loop
.Lloop:
    subs   r6, r6, #1
    ldrb   r1, [r3, r6]
    strb   r1, [r0, r6]
    bne    .Lloop
    // Store length since it is overwritten by memcpy
    strb   r2, [r0, r5]
    // Return
    bx     lr
    .p2align 2,0
data:
    // While this value isn't important, it is still read
    // from in the memcpy loop.
    .byte  1
end:
    // stack of values will be added here
    // helpers for driver, not part of code
    .section .rodata
    .globl INCR, DECR, UNDO, PEEK, SIZE
INCR: .word incr - begin
DECR: .word decr - begin
UNDO: .word undo - begin
PEEK: .word peek - begin
SIZE: .word end - func
```
Note that this assembly file **must be compiled by GAS or GCC**. Clang emits a garbage value for the label arithmetic at `movs.n`.
The code must be placed at a 2 bytes aligned, 4 byte misaligned address, and so must all the output pointers.
This is a doozy that can probably be optimized a lot. The main issue is that calling functions on ARM doesn't automatically make a call stack like x86, the `lr` register must be saved manually. Additionally, `bl` is a 4 byte instruction so calling a helper function has a 6 byte overhead.
This generates code by writing to a pointer. Since self modifying code is pretty tricky, here is a driver for Linux:
```
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
typedef volatile unsigned char vu8;
extern void func(vu8*);
// These are helpers in the asm file that mean I don't have to recalculate the lengths.
extern const int PEEK, UNDO, INCR, DECR, SIZE;
#define MAX_SIZE 4096
// Just calling the function pointer wouldn't work
// because the compiler expects me to follow a
// calling convention for some reason.
// Note that you must compile with -march=armv7-a
// (technically v5te+ will work as well) for blx.
static int call(vu8 *output, const volatile void *func)
{
    register int inout asm("r0") = (int)output;
    // ensure Thumb bit
    register int funcptr asm("r1") = 1 | (int)func;
    asm(
        "blx %1"
      : "+r" (inout), "+r" (funcptr)
      :
      : "r2", "r3", "r4", "r5", "r6", "r12", "lr", "cc", "memory"
    );
    return inout;
}
static vu8 *get_page(void)
{
    // Allocate a read/write page
    vu8 *ptr = mmap(
        NULL,
        MAX_SIZE,
        PROT_READ | PROT_WRITE,
        MAP_PRIVATE | MAP_ANONYMOUS,
        -1,
        0
    );
    if (ptr == MAP_FAILED || ptr == NULL) abort();
    // fill with UDF #0xDE to make out of bounds jumps crash
    memset((void *)ptr, 0xDE, MAX_SIZE);
    // Misalign so the pointer is not 4 byte aligned
    return ptr + 2;
}
static void make_exec(vu8 *ptr)
{
    // mark read/exec
    // No rwx here
    mprotect((char *)ptr - 2, MAX_SIZE, PROT_READ | PROT_EXEC);
    // clear instruction cache
    __builtin___clear_cache((char *)ptr - 2, (char *)ptr - 2 + MAX_SIZE);
}
static void peek(vu8 *ptr)
{
    int val = call(NULL, ptr + PEEK);
    printf("%d\n", val);
}
static vu8 *eval(vu8 *ptr, int func_offset)
{
    vu8 *output = get_page();
    call(output, ptr + func_offset);
    make_exec(output);
    peek(output);
    return output;
}
int main(void)
{
    printf("size: %d\n", SIZE);
    printf("offsets: %d %d %d %d\n", INCR, DECR, UNDO, PEEK);
    vu8 *A = get_page();
    call(A, func);
    make_exec(A);
    peek(A);
    vu8 *B = eval(A, INCR);
    vu8 *C = eval(B, INCR);
    vu8 *D = eval(C, INCR);
    vu8 *E = eval(D, UNDO);
    vu8 *F = eval(E, UNDO);
    vu8 *G = eval(F, DECR);
    peek(F);
}
```
The functions all use the same calling convention except for `peek` which follows AAPCS.
The input is `r0`, which is a pointer that is 2 byte aligned and 4 byte misaligned. The function will be written to this pointer.
The function clobbers r0-r6, which is not AAPCS compliant.
The way the code works is it replicates itself by literally reading itself, followed by a length, then a stack of values.
```
    code
    length
    values....
```
Each time a new value is added, the new value is appended and the length is incremented. When undo is called, the length is decremented.
The length and the values are all 8-bit integers, so this can only store up to 254 values (the stack is 1-indexed because of the length byte)
Currently, the functions will be stored at the following offsets in the output buffer. When calling these, remember that the lowest bit must be set as these are Thumb functions.
* `peek`: 0
* `undo`: 8
* `incr`: 18
* `decr`: 22
[Answer]
# [sclin](https://github.com/molarmanful/sclin), 64 bytes
```
0.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
```
[Try it here!](https://replit.com/@molarmanful/try-sclin) Returns `[ inc dec undo peek ]`.
For testing/convenience purposes, the following snippet:
```
; ."\n"++ n>< n>o
```
will output each code on separate lines for easy copy-pasting.
For example, running the initial code with the snippet:
```
; ."\n"++ n>< n>o
0.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
```
outputs:
```
"0"dup 1+.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
"0"dup 1-.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
"0"dup pop pop.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
"0"dup end.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
```
Running `inc`:
```
; ."\n"++ n>< n>o
"0"dup 1+.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
```
outputs:
```
"0""1"dup 1+.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
"0""1"dup 1-.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
"0""1"dup pop pop.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
"0""1"dup end.
,`">S form"map c><"dup "["1+""1-"\pop2*`"end"].".\n"g@"++"4*#
```
## Explanation
Somewhat prettified code:
```
0.
,` ( >S form ) map c>< "dup " [ "1+" "1-" \pop 2*` "end" ] .".\n" g@ \++ 4*#
```
This solution takes advantage of the stack to trivialize the history functionality; for example, undo becomes a simple matter of popping the stack.
* `,` ( >S form ) map c><` serializes the stack into a series of formatted number strings. This is because sclin constructs negative numbers as `1_` but string-formats numbers as `-1`; luckily, sclin can perform arithmetic on number strings.
* `"dup "` is code for "new item in history" (which, in this case, is simply duplicating the top of the stack).
* `[ "1+" "1-" \pop 2*` "end" ]` are the core `[ inc dec undo peek ]` codes.
* `.".\n"` is code for "execute the next line."
* `g@` gets the current line as a string, which allows for code generation in subsequent iterations.
* `\++ 4*#` vectorized-concatenates all the code pieces to create complete `[ inc dec undo peek ]` codes.
A concatenative solution in a concatenative language!
]