package calculator
import java.math.BigInteger

fun defineOperator( operatorString: String ): String {
    var isValid = operatorString.toIntOrNull()
    when{
        isValid != null -> return "-1"
    }
    when{
        operatorString.length % 2 == 0 -> return "+"
        operatorString == "=" -> return "-2"
        else -> return "-"
    }
}

fun defineLimits ( expression: List<String>, start: Int) : Int {
    var need = 0
    var end = start
    for ( i in start..expression.size ) {
        if (expression[i] == ")") {
            need -= 1
        }
        if (expression[i] == "("){
            need += 1
        }
        end = i
        if (need == 0) return end
    }
    return -1
}

fun evaluate( expressionList: List<String> ) : String {
    try {
        var i = 0
        var expression = expressionList.toMutableList()
        var size = expression.size
        var flag = 0
        while (i < size ) {
            if (expression[i] == "(") {
                flag = 1
                var subexpinicio = i
                var subexpfin = defineLimits(expression, subexpinicio)
                if ( subexpfin == -1 ){
                    throw IllegalArgumentException("Operator not valid")
                } else {
                    var subexp = expression.subList(subexpinicio+1, subexpfin).toMutableList()
                    var eval = evaluate(subexp)
                    var z = subexpinicio
                    while (z < subexpfin) {
                        expression.removeAt(subexpinicio)
                        z += 1
                        size -=1
                    }
                    expression[subexpinicio] = eval
                }
                i = 0
            } else if (expression[i] == ")" && flag == 0){
                throw IllegalArgumentException("Operator not valid")
            }else i++
        }
        i = 0
        size = expression.size
        while ( i < size - 2 ) {
            var op1 = expression[i].toBigInteger()
            var op2 = expression[i + 2].toBigInteger()
            var operator = expression[i + 1]

            when(operator) {
                "*" -> {
                    expression[i+2] = (op1 * op2).toString()
                    expression.removeAt(i)
                    expression.removeAt(i)
                    size -= 2
                    i = 0
                }
                "/" -> {
                    expression[i+2] = (op1 / op2).toString()
                    expression.removeAt(i)
                    expression.removeAt(i)
                    size -= 2
                    i = 0
                }
                else -> i += 2
            }
        }

        i = 0
        while ( i < size - 2 ) {
            var op1 = expression[i].toBigInteger()
            var op2 = expression[i + 2].toBigInteger()
            var operator = expression[i + 1]
            if( operator.length > 1 ) {
                operator = defineOperator(operator)
            }
            when(operator) {
                "+" -> expression[i+2] = (op1 + op2).toString()
                "-" -> expression[i+2] = (op1 - op2).toString()
                else -> throw IllegalArgumentException("Operator not valid")
            }
            i += 2
        }
        return expression.last()
    } catch (e : Exception) {
        return "Invalid expression"
    }
}

fun isLetters(string: String): Boolean {
    return string.all { it in 'A'..'Z' || it in 'a'..'z' }
}

fun isNumbers(string: String): Boolean {
    return string.all { it in '0'..'9' }
}

fun main() {
    var variables = mutableMapOf<String, BigInteger>()
    loop@ while(true) {
        var input = readLine()!!.replace("\\=".toRegex(), "eq=eq").replace("\\(".toRegex(), "(par").replace("\\)".toRegex(), "par)").replace("\\++".toRegex(), "plus+plus").replace("(?<!-)-(--)*(?!-|\\d)".toRegex(), "minus-minus").replace("\\--+".toRegex(), "plus+plus").replace("\\*".toRegex(), "mul*mul").replace("\\/(?!\\d|\\w)".toRegex(), "div/div").replace("\\s".toRegex(), "")
        var expression = input.split("plus|minus|eq|mul|div|par".toRegex()).toMutableList()
        var eval: String = ""
        when {
            expression[0] == "/help" -> {
                println("sdads")
                continue
            }
            expression[0] == "/exit" -> break
            expression[0].startsWith('/') -> {
                println("Unknown Command")
                continue
            }
            expression.size == 1 && expression[0] == "" -> continue
            expression.size == 1 && isLetters(expression[0]) -> {
                when {
                    variables.containsKey(expression[0]) -> {
                        println(variables[expression[0]])
                        continue
                    }
                    else -> {
                        println("Unknown variable")
                        continue
                    }
                }
            }
            expression.size == 3 && expression[1] == "=" -> {
                when {
                    isLetters(expression[0]) && !isLetters(expression[2]) -> {
                        try {
                            variables[expression[0]] = expression[2].toBigInteger()
                            continue
                        } catch (e: Exception){
                            println("Invalid expression")
                            continue
                        }
                    }
                    isLetters(expression[0]) && isLetters(expression[2]) -> {
                        when  {
                            variables.containsKey(expression[2]) ->{
                                variables[expression[0]] = variables[expression[2]]!!
                                continue
                            }
                            else -> {
                                println("Invalid assignment")
                                continue
                            }
                        }
                    }
                    else -> {
                        println("Invalid identifier")
                        continue
                    }
                }
            }
            expression.size == 3 -> {
                println(evaluate(expression))
                continue
            }
            expression.size > 3 -> {
                for (i in expression.indices) {
                    if ( i > 1 && expression[i] == "="){
                        println("Invalid assignment")
                        continue@loop
                    }
                }
                when {
                    expression[1] == "=" -> when {
                        isLetters(expression[0]) -> {
                            variables[expression[0]] = evaluate(expression.subList(2, expression.size - 1)).toBigInteger()
                            continue
                        }
                        else -> continue
                    }
                    else->{
                        for (i in expression.indices) {
                            if (isLetters(expression[i])) {
                                when {
                                    variables.containsKey(expression[i]) -> expression[i] = variables[expression[i]].toString()
                                    else -> {
                                        continue
                                    }
                                }
                            }
                        }
                        println(evaluate(expression))
                        continue
                    }
                }
            }
            else -> println(expression)

        }
        break
    }
    println("Bye")
}

Compiled from "smartcalc.kt"
public final class calculator.SmartcalcKt {
  public static final java.lang.String defineOperator(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #9                  // String operatorString
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokestatic  #21                 // Method kotlin/text/StringsKt.toIntOrNull:(Ljava/lang/String;)Ljava/lang/Integer;
      10: astore_1
      11: nop
      12: aload_1
      13: ifnull        19
      16: ldc           #23                 // String -1
      18: areturn
      19: nop
      20: aload_0
      21: invokevirtual #29                 // Method java/lang/String.length:()I
      24: iconst_2
      25: irem
      26: ifne          32
      29: ldc           #31                 // String +
      31: areturn
      32: aload_0
      33: ldc           #33                 // String =
      35: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      38: ifeq          44
      41: ldc           #39                 // String -2
      43: areturn
      44: ldc           #41                 // String -
      46: areturn

  public static final int defineLimits(java.util.List<java.lang.String>, int);
    Code:
       0: aload_0
       1: ldc           #51                 // String expression
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: iconst_0
       7: istore_2
       8: iload_1
       9: istore_3
      10: iload_1
      11: istore        4
      13: aload_0
      14: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
      19: istore        5
      21: iload         4
      23: iload         5
      25: if_icmpgt     88
      28: aload_0
      29: iload         4
      31: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      36: ldc           #62                 // String )
      38: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      41: ifeq          47
      44: iinc          2, -1
      47: aload_0
      48: iload         4
      50: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      55: ldc           #64                 // String (
      57: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      60: ifeq          66
      63: iinc          2, 1
      66: iload         4
      68: istore_3
      69: iload_2
      70: ifne          75
      73: iload_3
      74: ireturn
      75: iload         4
      77: iload         5
      79: if_icmpeq     88
      82: iinc          4, 1
      85: goto          28
      88: iconst_m1
      89: ireturn

  public static final java.lang.String evaluate(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: ldc           #77                 // String expressionList
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: nop
       7: iconst_0
       8: istore_1
       9: aload_0
      10: checkcast     #79                 // class java/util/Collection
      13: invokestatic  #85                 // Method kotlin/collections/CollectionsKt.toMutableList:(Ljava/util/Collection;)Ljava/util/List;
      16: astore_2
      17: aload_2
      18: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
      23: istore_3
      24: iconst_0
      25: istore        4
      27: iload_1
      28: iload_3
      29: if_icmpge     187
      32: aload_2
      33: iload_1
      34: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      39: ldc           #64                 // String (
      41: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      44: ifeq          149
      47: iconst_1
      48: istore        4
      50: iload_1
      51: istore        5
      53: aload_2
      54: iload         5
      56: invokestatic  #87                 // Method defineLimits:(Ljava/util/List;I)I
      59: istore        6
      61: iload         6
      63: iconst_m1
      64: if_icmpne     77
      67: new           #89                 // class java/lang/IllegalArgumentException
      70: dup
      71: ldc           #91                 // String Operator not valid
      73: invokespecial #95                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
      76: athrow
      77: aload_2
      78: iload         5
      80: iconst_1
      81: iadd
      82: iload         6
      84: invokeinterface #99,  3           // InterfaceMethod java/util/List.subList:(II)Ljava/util/List;
      89: checkcast     #79                 // class java/util/Collection
      92: invokestatic  #85                 // Method kotlin/collections/CollectionsKt.toMutableList:(Ljava/util/Collection;)Ljava/util/List;
      95: astore        7
      97: aload         7
      99: invokestatic  #101                // Method evaluate:(Ljava/util/List;)Ljava/lang/String;
     102: astore        8
     104: iload         5
     106: istore        9
     108: iload         9
     110: iload         6
     112: if_icmpge     133
     115: aload_2
     116: iload         5
     118: invokeinterface #104,  2          // InterfaceMethod java/util/List.remove:(I)Ljava/lang/Object;
     123: pop
     124: iinc          9, 1
     127: iinc          3, -1
     130: goto          108
     133: aload_2
     134: iload         5
     136: aload         8
     138: invokeinterface #108,  3          // InterfaceMethod java/util/List.set:(ILjava/lang/Object;)Ljava/lang/Object;
     143: pop
     144: iconst_0
     145: istore_1
     146: goto          27
     149: aload_2
     150: iload_1
     151: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     156: ldc           #62                 // String )
     158: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     161: ifeq          179
     164: iload         4
     166: ifne          179
     169: new           #89                 // class java/lang/IllegalArgumentException
     172: dup
     173: ldc           #91                 // String Operator not valid
     175: invokespecial #95                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
     178: athrow
     179: iload_1
     180: iinc          1, 1
     183: pop
     184: goto          27
     187: iconst_0
     188: istore_1
     189: aload_2
     190: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
     195: istore_3
     196: iload_1
     197: iload_3
     198: iconst_2
     199: isub
     200: if_icmpge     399
     203: new           #110                // class java/math/BigInteger
     206: dup
     207: aload_2
     208: iload_1
     209: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     214: checkcast     #25                 // class java/lang/String
     217: invokespecial #111                // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
     220: astore        5
     222: new           #110                // class java/math/BigInteger
     225: dup
     226: aload_2
     227: iload_1
     228: iconst_2
     229: iadd
     230: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     235: checkcast     #25                 // class java/lang/String
     238: invokespecial #111                // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
     241: astore        6
     243: aload_2
     244: iload_1
     245: iconst_1
     246: iadd
     247: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     252: checkcast     #25                 // class java/lang/String
     255: astore        7
     257: aload         7
     259: astore        8
     261: aload         8
     263: ldc           #113                // String *
     265: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     268: ifeq          327
     271: aload_2
     272: iload_1
     273: iconst_2
     274: iadd
     275: aload         5
     277: aload         6
     279: invokevirtual #117                // Method java/math/BigInteger.multiply:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
     282: dup
     283: ldc           #119                // String multiply(...)
     285: invokestatic  #122                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     288: invokevirtual #126                // Method java/math/BigInteger.toString:()Ljava/lang/String;
     291: dup
     292: ldc           #128                // String toString(...)
     294: invokestatic  #122                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     297: invokeinterface #108,  3          // InterfaceMethod java/util/List.set:(ILjava/lang/Object;)Ljava/lang/Object;
     302: pop
     303: aload_2
     304: iload_1
     305: invokeinterface #104,  2          // InterfaceMethod java/util/List.remove:(I)Ljava/lang/Object;
     310: pop
     311: aload_2
     312: iload_1
     313: invokeinterface #104,  2          // InterfaceMethod java/util/List.remove:(I)Ljava/lang/Object;
     318: pop
     319: iinc          3, -2
     322: iconst_0
     323: istore_1
     324: goto          196
     327: aload         8
     329: ldc           #130                // String /
     331: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     334: ifeq          393
     337: aload_2
     338: iload_1
     339: iconst_2
     340: iadd
     341: aload         5
     343: aload         6
     345: invokevirtual #133                // Method java/math/BigInteger.divide:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
     348: dup
     349: ldc           #135                // String divide(...)
     351: invokestatic  #122                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     354: invokevirtual #126                // Method java/math/BigInteger.toString:()Ljava/lang/String;
     357: dup
     358: ldc           #128                // String toString(...)
     360: invokestatic  #122                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     363: invokeinterface #108,  3          // InterfaceMethod java/util/List.set:(ILjava/lang/Object;)Ljava/lang/Object;
     368: pop
     369: aload_2
     370: iload_1
     371: invokeinterface #104,  2          // InterfaceMethod java/util/List.remove:(I)Ljava/lang/Object;
     376: pop
     377: aload_2
     378: iload_1
     379: invokeinterface #104,  2          // InterfaceMethod java/util/List.remove:(I)Ljava/lang/Object;
     384: pop
     385: iinc          3, -2
     388: iconst_0
     389: istore_1
     390: goto          196
     393: iinc          1, 2
     396: goto          196
     399: iconst_0
     400: istore_1
     401: iload_1
     402: iload_3
     403: iconst_2
     404: isub
     405: if_icmpge     588
     408: new           #110                // class java/math/BigInteger
     411: dup
     412: aload_2
     413: iload_1
     414: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     419: checkcast     #25                 // class java/lang/String
     422: invokespecial #111                // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
     425: astore        5
     427: new           #110                // class java/math/BigInteger
     430: dup
     431: aload_2
     432: iload_1
     433: iconst_2
     434: iadd
     435: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     440: checkcast     #25                 // class java/lang/String
     443: invokespecial #111                // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
     446: astore        6
     448: aload_2
     449: iload_1
     450: iconst_1
     451: iadd
     452: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     457: checkcast     #25                 // class java/lang/String
     460: astore        7
     462: aload         7
     464: invokevirtual #29                 // Method java/lang/String.length:()I
     467: iconst_1
     468: if_icmple     478
     471: aload         7
     473: invokestatic  #137                // Method defineOperator:(Ljava/lang/String;)Ljava/lang/String;
     476: astore        7
     478: aload         7
     480: astore        8
     482: aload         8
     484: ldc           #31                 // String +
     486: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     489: ifeq          527
     492: aload_2
     493: iload_1
     494: iconst_2
     495: iadd
     496: aload         5
     498: aload         6
     500: invokevirtual #140                // Method java/math/BigInteger.add:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
     503: dup
     504: ldc           #142                // String add(...)
     506: invokestatic  #122                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     509: invokevirtual #126                // Method java/math/BigInteger.toString:()Ljava/lang/String;
     512: dup
     513: ldc           #128                // String toString(...)
     515: invokestatic  #122                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     518: invokeinterface #108,  3          // InterfaceMethod java/util/List.set:(ILjava/lang/Object;)Ljava/lang/Object;
     523: pop
     524: goto          582
     527: aload         8
     529: ldc           #41                 // String -
     531: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     534: ifeq          572
     537: aload_2
     538: iload_1
     539: iconst_2
     540: iadd
     541: aload         5
     543: aload         6
     545: invokevirtual #145                // Method java/math/BigInteger.subtract:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
     548: dup
     549: ldc           #147                // String subtract(...)
     551: invokestatic  #122                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     554: invokevirtual #126                // Method java/math/BigInteger.toString:()Ljava/lang/String;
     557: dup
     558: ldc           #128                // String toString(...)
     560: invokestatic  #122                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     563: invokeinterface #108,  3          // InterfaceMethod java/util/List.set:(ILjava/lang/Object;)Ljava/lang/Object;
     568: pop
     569: goto          582
     572: new           #89                 // class java/lang/IllegalArgumentException
     575: dup
     576: ldc           #91                 // String Operator not valid
     578: invokespecial #95                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
     581: athrow
     582: iinc          1, 2
     585: goto          401
     588: aload_2
     589: invokestatic  #151                // Method kotlin/collections/CollectionsKt.last:(Ljava/util/List;)Ljava/lang/Object;
     592: checkcast     #25                 // class java/lang/String
     595: areturn
     596: astore_2
     597: ldc           #153                // String Invalid expression
     599: areturn
    Exception table:
       from    to  target type
           6   596   596   Class java/lang/Exception

  public static final boolean isLetters(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #169                // String string
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #171                // class java/lang/CharSequence
      10: astore_1
      11: iconst_0
      12: istore_2
      13: iconst_0
      14: istore_3
      15: iload_3
      16: aload_1
      17: invokeinterface #172,  1          // InterfaceMethod java/lang/CharSequence.length:()I
      22: if_icmpge     111
      25: aload_1
      26: iload_3
      27: invokeinterface #176,  2          // InterfaceMethod java/lang/CharSequence.charAt:(I)C
      32: istore        4
      34: iload         4
      36: istore        5
      38: iconst_0
      39: istore        6
      41: bipush        65
      43: iload         5
      45: if_icmpgt     63
      48: iload         5
      50: bipush        91
      52: if_icmpge     59
      55: iconst_1
      56: goto          64
      59: iconst_0
      60: goto          64
      63: iconst_0
      64: ifne          93
      67: bipush        97
      69: iload         5
      71: if_icmpgt     89
      74: iload         5
      76: bipush        123
      78: if_icmpge     85
      81: iconst_1
      82: goto          90
      85: iconst_0
      86: goto          90
      89: iconst_0
      90: ifeq          97
      93: iconst_1
      94: goto          98
      97: iconst_0
      98: ifne          105
     101: iconst_0
     102: goto          112
     105: iinc          3, 1
     108: goto          15
     111: iconst_1
     112: ireturn

  public static final boolean isNumbers(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #169                // String string
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #171                // class java/lang/CharSequence
      10: astore_1
      11: iconst_0
      12: istore_2
      13: iconst_0
      14: istore_3
      15: iload_3
      16: aload_1
      17: invokeinterface #172,  1          // InterfaceMethod java/lang/CharSequence.length:()I
      22: if_icmpge     77
      25: aload_1
      26: iload_3
      27: invokeinterface #176,  2          // InterfaceMethod java/lang/CharSequence.charAt:(I)C
      32: istore        4
      34: iload         4
      36: istore        5
      38: iconst_0
      39: istore        6
      41: bipush        48
      43: iload         5
      45: if_icmpgt     63
      48: iload         5
      50: bipush        58
      52: if_icmpge     59
      55: iconst_1
      56: goto          64
      59: iconst_0
      60: goto          64
      63: iconst_0
      64: ifne          71
      67: iconst_0
      68: goto          78
      71: iinc          3, 1
      74: goto          15
      77: iconst_1
      78: ireturn

  public static final void main();
    Code:
       0: new           #189                // class java/util/LinkedHashMap
       3: dup
       4: invokespecial #191                // Method java/util/LinkedHashMap."<init>":()V
       7: checkcast     #193                // class java/util/Map
      10: astore_0
      11: nop
      12: invokestatic  #198                // Method kotlin/io/ConsoleKt.readLine:()Ljava/lang/String;
      15: dup
      16: invokestatic  #202                // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
      19: checkcast     #171                // class java/lang/CharSequence
      22: astore_2
      23: new           #204                // class kotlin/text/Regex
      26: dup
      27: ldc           #206                // String \\=
      29: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
      32: astore_3
      33: ldc           #209                // String eq=eq
      35: astore        4
      37: aload_3
      38: aload_2
      39: aload         4
      41: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
      44: checkcast     #171                // class java/lang/CharSequence
      47: astore_2
      48: new           #204                // class kotlin/text/Regex
      51: dup
      52: ldc           #215                // String \\(
      54: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
      57: astore_3
      58: ldc           #217                // String (par
      60: astore        4
      62: aload_3
      63: aload_2
      64: aload         4
      66: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
      69: checkcast     #171                // class java/lang/CharSequence
      72: astore_2
      73: new           #204                // class kotlin/text/Regex
      76: dup
      77: ldc           #219                // String \\)
      79: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
      82: astore_3
      83: ldc           #221                // String par)
      85: astore        4
      87: aload_3
      88: aload_2
      89: aload         4
      91: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
      94: checkcast     #171                // class java/lang/CharSequence
      97: astore_2
      98: new           #204                // class kotlin/text/Regex
     101: dup
     102: ldc           #223                // String \\++
     104: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
     107: astore_3
     108: ldc           #225                // String plus+plus
     110: astore        4
     112: aload_3
     113: aload_2
     114: aload         4
     116: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
     119: checkcast     #171                // class java/lang/CharSequence
     122: astore_2
     123: new           #204                // class kotlin/text/Regex
     126: dup
     127: ldc           #227                // String (?<!-)-(--)*(?!-|\\d)
     129: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
     132: astore_3
     133: ldc           #229                // String minus-minus
     135: astore        4
     137: aload_3
     138: aload_2
     139: aload         4
     141: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
     144: checkcast     #171                // class java/lang/CharSequence
     147: astore_2
     148: new           #204                // class kotlin/text/Regex
     151: dup
     152: ldc           #231                // String \\--+
     154: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
     157: astore_3
     158: ldc           #225                // String plus+plus
     160: astore        4
     162: aload_3
     163: aload_2
     164: aload         4
     166: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
     169: checkcast     #171                // class java/lang/CharSequence
     172: astore_2
     173: new           #204                // class kotlin/text/Regex
     176: dup
     177: ldc           #233                // String \\*
     179: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
     182: astore_3
     183: ldc           #235                // String mul*mul
     185: astore        4
     187: aload_3
     188: aload_2
     189: aload         4
     191: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
     194: checkcast     #171                // class java/lang/CharSequence
     197: astore_2
     198: new           #204                // class kotlin/text/Regex
     201: dup
     202: ldc           #237                // String \\/(?!\\d|\\w)
     204: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
     207: astore_3
     208: ldc           #239                // String div/div
     210: astore        4
     212: aload_3
     213: aload_2
     214: aload         4
     216: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
     219: checkcast     #171                // class java/lang/CharSequence
     222: astore_2
     223: new           #204                // class kotlin/text/Regex
     226: dup
     227: ldc           #241                // String \\s
     229: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
     232: astore_3
     233: ldc           #243                // String
     235: astore        4
     237: aload_3
     238: aload_2
     239: aload         4
     241: invokevirtual #213                // Method kotlin/text/Regex.replace:(Ljava/lang/CharSequence;Ljava/lang/String;)Ljava/lang/String;
     244: astore_1
     245: aload_1
     246: checkcast     #171                // class java/lang/CharSequence
     249: astore_3
     250: new           #204                // class kotlin/text/Regex
     253: dup
     254: ldc           #245                // String plus|minus|eq|mul|div|par
     256: invokespecial #207                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
     259: astore        4
     261: iconst_0
     262: istore        5
     264: aload         4
     266: aload_3
     267: iload         5
     269: invokevirtual #249                // Method kotlin/text/Regex.split:(Ljava/lang/CharSequence;I)Ljava/util/List;
     272: checkcast     #79                 // class java/util/Collection
     275: invokestatic  #85                 // Method kotlin/collections/CollectionsKt.toMutableList:(Ljava/util/Collection;)Ljava/util/List;
     278: astore_2
     279: ldc           #243                // String
     281: astore_3
     282: nop
     283: aload_2
     284: iconst_0
     285: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     290: ldc           #251                // String /help
     292: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     295: ifeq          310
     298: ldc           #253                // String sdads
     300: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     303: swap
     304: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     307: goto          11
     310: aload_2
     311: iconst_0
     312: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     317: ldc_w         #266                // String /exit
     320: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     323: ifne          969
     326: aload_2
     327: iconst_0
     328: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     333: checkcast     #171                // class java/lang/CharSequence
     336: bipush        47
     338: iconst_0
     339: iconst_2
     340: aconst_null
     341: invokestatic  #270                // Method kotlin/text/StringsKt.startsWith$default:(Ljava/lang/CharSequence;CZILjava/lang/Object;)Z
     344: ifeq          360
     347: ldc_w         #272                // String Unknown Command
     350: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     353: swap
     354: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     357: goto          11
     360: aload_2
     361: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
     366: iconst_1
     367: if_icmpne     385
     370: aload_2
     371: iconst_0
     372: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     377: ldc           #243                // String
     379: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     382: ifne          11
     385: aload_2
     386: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
     391: iconst_1
     392: if_icmpne     464
     395: aload_2
     396: iconst_0
     397: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     402: checkcast     #25                 // class java/lang/String
     405: invokestatic  #274                // Method isLetters:(Ljava/lang/String;)Z
     408: ifeq          464
     411: nop
     412: aload_0
     413: aload_2
     414: iconst_0
     415: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     420: invokeinterface #278,  2          // InterfaceMethod java/util/Map.containsKey:(Ljava/lang/Object;)Z
     425: ifeq          451
     428: aload_0
     429: aload_2
     430: iconst_0
     431: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     436: invokeinterface #281,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     441: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     444: swap
     445: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     448: goto          11
     451: ldc_w         #283                // String Unknown variable
     454: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     457: swap
     458: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     461: goto          11
     464: aload_2
     465: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
     470: iconst_3
     471: if_icmpne     681
     474: aload_2
     475: iconst_1
     476: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     481: ldc           #33                 // String =
     483: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     486: ifeq          681
     489: nop
     490: aload_2
     491: iconst_0
     492: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     497: checkcast     #25                 // class java/lang/String
     500: invokestatic  #274                // Method isLetters:(Ljava/lang/String;)Z
     503: ifeq          572
     506: aload_2
     507: iconst_2
     508: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     513: checkcast     #25                 // class java/lang/String
     516: invokestatic  #274                // Method isLetters:(Ljava/lang/String;)Z
     519: ifne          572
     522: nop
     523: nop
     524: aload_0
     525: aload_2
     526: iconst_0
     527: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     532: new           #110                // class java/math/BigInteger
     535: dup
     536: aload_2
     537: iconst_2
     538: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     543: checkcast     #25                 // class java/lang/String
     546: invokespecial #111                // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
     549: invokeinterface #287,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     554: pop
     555: goto          11
     558: astore        5
     560: ldc           #153                // String Invalid expression
     562: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     565: swap
     566: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     569: goto          11
     572: aload_2
     573: iconst_0
     574: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     579: checkcast     #25                 // class java/lang/String
     582: invokestatic  #274                // Method isLetters:(Ljava/lang/String;)Z
     585: ifeq          668
     588: aload_2
     589: iconst_2
     590: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     595: checkcast     #25                 // class java/lang/String
     598: invokestatic  #274                // Method isLetters:(Ljava/lang/String;)Z
     601: ifeq          668
     604: nop
     605: aload_0
     606: aload_2
     607: iconst_2
     608: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     613: invokeinterface #278,  2          // InterfaceMethod java/util/Map.containsKey:(Ljava/lang/Object;)Z
     618: ifeq          655
     621: aload_0
     622: aload_2
     623: iconst_0
     624: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     629: aload_0
     630: aload_2
     631: iconst_2
     632: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     637: invokeinterface #281,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     642: dup
     643: invokestatic  #202                // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
     646: invokeinterface #287,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     651: pop
     652: goto          11
     655: ldc_w         #289                // String Invalid assignment
     658: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     661: swap
     662: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     665: goto          11
     668: ldc_w         #291                // String Invalid identifier
     671: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     674: swap
     675: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     678: goto          11
     681: aload_2
     682: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
     687: iconst_3
     688: if_icmpne     705
     691: aload_2
     692: invokestatic  #101                // Method evaluate:(Ljava/util/List;)Ljava/lang/String;
     695: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     698: swap
     699: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     702: goto          11
     705: aload_2
     706: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
     711: iconst_3
     712: if_icmple     961
     715: iconst_0
     716: istore        4
     718: aload_2
     719: checkcast     #79                 // class java/util/Collection
     722: invokeinterface #292,  1          // InterfaceMethod java/util/Collection.size:()I
     727: istore        5
     729: iload         4
     731: iload         5
     733: if_icmpge     777
     736: iload         4
     738: iconst_1
     739: if_icmple     771
     742: aload_2
     743: iload         4
     745: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     750: ldc           #33                 // String =
     752: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     755: ifeq          771
     758: ldc_w         #289                // String Invalid assignment
     761: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     764: swap
     765: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     768: goto          11
     771: iinc          4, 1
     774: goto          729
     777: nop
     778: aload_2
     779: iconst_1
     780: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     785: ldc           #33                 // String =
     787: invokestatic  #37                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     790: ifeq          855
     793: aload_2
     794: iconst_0
     795: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     800: checkcast     #25                 // class java/lang/String
     803: invokestatic  #274                // Method isLetters:(Ljava/lang/String;)Z
     806: ifeq          852
     809: nop
     810: aload_0
     811: aload_2
     812: iconst_0
     813: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     818: new           #110                // class java/math/BigInteger
     821: dup
     822: aload_2
     823: iconst_2
     824: aload_2
     825: invokeinterface #56,  1           // InterfaceMethod java/util/List.size:()I
     830: iconst_1
     831: isub
     832: invokeinterface #99,  3           // InterfaceMethod java/util/List.subList:(II)Ljava/util/List;
     837: invokestatic  #101                // Method evaluate:(Ljava/util/List;)Ljava/lang/String;
     840: invokespecial #111                // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
     843: invokeinterface #287,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     848: pop
     849: goto          11
     852: goto          11
     855: iconst_0
     856: istore        4
     858: aload_2
     859: checkcast     #79                 // class java/util/Collection
     862: invokeinterface #292,  1          // InterfaceMethod java/util/Collection.size:()I
     867: istore        5
     869: iload         4
     871: iload         5
     873: if_icmpge     947
     876: aload_2
     877: iload         4
     879: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     884: checkcast     #25                 // class java/lang/String
     887: invokestatic  #274                // Method isLetters:(Ljava/lang/String;)Z
     890: ifeq          941
     893: nop
     894: aload_0
     895: aload_2
     896: iload         4
     898: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     903: invokeinterface #278,  2          // InterfaceMethod java/util/Map.containsKey:(Ljava/lang/Object;)Z
     908: ifeq          940
     911: aload_2
     912: iload         4
     914: aload_0
     915: aload_2
     916: iload         4
     918: invokeinterface #60,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     923: invokeinterface #281,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     928: invokestatic  #296                // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
     931: invokeinterface #108,  3          // InterfaceMethod java/util/List.set:(ILjava/lang/Object;)Ljava/lang/Object;
     936: pop
     937: goto          941
     940: nop
     941: iinc          4, 1
     944: goto          869
     947: aload_2
     948: invokestatic  #101                // Method evaluate:(Ljava/util/List;)Ljava/lang/String;
     951: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     954: swap
     955: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     958: goto          11
     961: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     964: aload_2
     965: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     968: nop
     969: ldc_w         #298                // String Bye
     972: getstatic     #259                // Field java/lang/System.out:Ljava/io/PrintStream;
     975: swap
     976: invokevirtual #264                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     979: return
    Exception table:
       from    to  target type
         522   558   558   Class java/lang/Exception

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #304                // Method main:()V
       3: return
}


package de.rieckpil.learning.fpbook

fun main() {
  println(fib(10))
  println(fib(2))
  println(fib(1))
  println(fib(0))
  println(factorial(7))
  println(findFirst(arrayOf("Duke", "Foo", "Mike", "Phil", "Tom")) { it == "Phil" })
  println(findFirst(arrayOf(true, false, true, false)) { !it })
  println(isSorted(listOf(1, 10, 20, 30)) { x, y ->
    x < y
  })
  println(isSorted(listOf("Mike", "Hansi", "Dukeduke", "Alphabetz")) { x, y ->
    x.length < y.length
  })

  val curry = curry { i: Int, s: String -> s[i] }
  println(curry(1)("Hello"))

  val uncurry = uncurry { i: Int -> { s: String -> s[i] } }
  println(uncurry(1, "Hello"))

}

/**
 * Chapter II
 */

fun factorial(i: Int): Int {
  tailrec fun go(n: Int, acc: Int): Int =
    if (n <= 0) acc
    else go(n - 1, n * acc)
  return go(i, 1)
}

fun fib(i: Int): Int {
  tailrec fun go(n: Int): Int =
    if (n <= 1) n
    else go(n - 1) + go(n - 2)
  return go(i)
}

fun <A> findFirst(xs: Array<A>, p: (A) -> Boolean): Int {
  tailrec fun loop(n: Int): Int =
    when {
      n >= xs.size -> -1
      p(xs[n]) -> n
      else -> loop(n + 1)
    }
  return loop(0)
}

val <T> List<T>.tail: List<T>
  get() = drop(1)

val <T> List<T>.head: T
  get() = first()

fun <A> isSorted(aa: List<A>, ordered: (A, A) -> Boolean): Boolean {
  tailrec fun loop(head: A, tail: List<A>): Boolean =
    when {
      head == null -> true
      tail.isEmpty() -> true
      ordered(head, tail.head) -> loop(tail.head, tail.tail)
      else -> false
    }
  return loop(aa.head, aa.tail)
}

fun <A, B, C> partiall(a: A, f: (A, B) -> C): (B) -> C = { b -> f(a, b) }

fun <A, B, C> curry(f: (A, B) -> C): (A) -> (B) -> C = { a -> { b -> f(a, b) } }

fun <A, B, C> uncurry(f: (A) -> (B) -> C): (A, B) -> C = { a: A, b: B -> f(a)(b) }

fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C = { f(g(it)) }

Compiled from "fpBook.kt"
public final class de.rieckpil.learning.fpbook.FpBookKt {
  public static final void main();
    Code:
       0: bipush        10
       2: invokestatic  #10                 // Method fib:(I)I
       5: istore_0
       6: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       9: iload_0
      10: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      13: iconst_2
      14: invokestatic  #10                 // Method fib:(I)I
      17: istore_0
      18: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      21: iload_0
      22: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      25: iconst_1
      26: invokestatic  #10                 // Method fib:(I)I
      29: istore_0
      30: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      33: iload_0
      34: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      37: iconst_0
      38: invokestatic  #10                 // Method fib:(I)I
      41: istore_0
      42: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      45: iload_0
      46: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      49: bipush        7
      51: invokestatic  #25                 // Method factorial:(I)I
      54: istore_0
      55: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      58: iload_0
      59: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
      62: iconst_5
      63: anewarray     #27                 // class java/lang/String
      66: astore_0
      67: aload_0
      68: iconst_0
      69: ldc           #29                 // String Duke
      71: aastore
      72: aload_0
      73: iconst_1
      74: ldc           #31                 // String Foo
      76: aastore
      77: aload_0
      78: iconst_2
      79: ldc           #33                 // String Mike
      81: aastore
      82: aload_0
      83: iconst_3
      84: ldc           #35                 // String Phil
      86: aastore
      87: aload_0
      88: iconst_4
      89: ldc           #37                 // String Tom
      91: aastore
      92: aload_0
      93: invokedynamic #57,  0             // InvokeDynamic #0:invoke:()Lkotlin/jvm/functions/Function1;
      98: invokestatic  #61                 // Method findFirst:([Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)I
     101: istore_0
     102: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
     105: iload_0
     106: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
     109: iconst_4
     110: anewarray     #63                 // class java/lang/Boolean
     113: astore_0
     114: aload_0
     115: iconst_0
     116: iconst_1
     117: invokestatic  #67                 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
     120: aastore
     121: aload_0
     122: iconst_1
     123: iconst_0
     124: invokestatic  #67                 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
     127: aastore
     128: aload_0
     129: iconst_2
     130: iconst_1
     131: invokestatic  #67                 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
     134: aastore
     135: aload_0
     136: iconst_3
     137: iconst_0
     138: invokestatic  #67                 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
     141: aastore
     142: aload_0
     143: invokedynamic #75,  0             // InvokeDynamic #1:invoke:()Lkotlin/jvm/functions/Function1;
     148: invokestatic  #61                 // Method findFirst:([Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)I
     151: istore_0
     152: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
     155: iload_0
     156: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
     159: iconst_4
     160: anewarray     #77                 // class java/lang/Integer
     163: astore_0
     164: aload_0
     165: iconst_0
     166: iconst_1
     167: invokestatic  #80                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     170: aastore
     171: aload_0
     172: iconst_1
     173: bipush        10
     175: invokestatic  #80                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     178: aastore
     179: aload_0
     180: iconst_2
     181: bipush        20
     183: invokestatic  #80                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     186: aastore
     187: aload_0
     188: iconst_3
     189: bipush        30
     191: invokestatic  #80                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     194: aastore
     195: aload_0
     196: invokestatic  #86                 // Method kotlin/collections/CollectionsKt.listOf:([Ljava/lang/Object;)Ljava/util/List;
     199: invokedynamic #98,  0             // InvokeDynamic #2:invoke:()Lkotlin/jvm/functions/Function2;
     204: invokestatic  #102                // Method isSorted:(Ljava/util/List;Lkotlin/jvm/functions/Function2;)Z
     207: istore_0
     208: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
     211: iload_0
     212: invokevirtual #105                // Method java/io/PrintStream.println:(Z)V
     215: iconst_4
     216: anewarray     #27                 // class java/lang/String
     219: astore_0
     220: aload_0
     221: iconst_0
     222: ldc           #33                 // String Mike
     224: aastore
     225: aload_0
     226: iconst_1
     227: ldc           #107                // String Hansi
     229: aastore
     230: aload_0
     231: iconst_2
     232: ldc           #109                // String Dukeduke
     234: aastore
     235: aload_0
     236: iconst_3
     237: ldc           #111                // String Alphabetz
     239: aastore
     240: aload_0
     241: invokestatic  #86                 // Method kotlin/collections/CollectionsKt.listOf:([Ljava/lang/Object;)Ljava/util/List;
     244: invokedynamic #119,  0            // InvokeDynamic #3:invoke:()Lkotlin/jvm/functions/Function2;
     249: invokestatic  #102                // Method isSorted:(Ljava/util/List;Lkotlin/jvm/functions/Function2;)Z
     252: istore_0
     253: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
     256: iload_0
     257: invokevirtual #105                // Method java/io/PrintStream.println:(Z)V
     260: invokedynamic #127,  0            // InvokeDynamic #4:invoke:()Lkotlin/jvm/functions/Function2;
     265: invokestatic  #131                // Method curry:(Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function1;
     268: astore_0
     269: aload_0
     270: iconst_1
     271: invokestatic  #80                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     274: invokeinterface #135,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
     279: checkcast     #133                // class kotlin/jvm/functions/Function1
     282: ldc           #137                // String Hello
     284: invokeinterface #135,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
     289: checkcast     #139                // class java/lang/Character
     292: invokevirtual #143                // Method java/lang/Character.charValue:()C
     295: istore_1
     296: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
     299: iload_1
     300: invokevirtual #146                // Method java/io/PrintStream.println:(C)V
     303: invokedynamic #154,  0            // InvokeDynamic #5:invoke:()Lkotlin/jvm/functions/Function1;
     308: invokestatic  #158                // Method uncurry:(Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function2;
     311: astore_1
     312: aload_1
     313: iconst_1
     314: invokestatic  #80                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     317: ldc           #137                // String Hello
     319: invokeinterface #162,  3          // InterfaceMethod kotlin/jvm/functions/Function2.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     324: checkcast     #139                // class java/lang/Character
     327: invokevirtual #143                // Method java/lang/Character.charValue:()C
     330: istore_2
     331: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
     334: iload_2
     335: invokevirtual #146                // Method java/io/PrintStream.println:(C)V
     338: return

  public static final int factorial(int);
    Code:
       0: iload_0
       1: iconst_1
       2: invokestatic  #168                // Method factorial$go:(II)I
       5: ireturn

  public static final int fib(int);
    Code:
       0: iload_0
       1: invokestatic  #173                // Method fib$go$7:(I)I
       4: ireturn

  public static final <A> int findFirst(A[], kotlin.jvm.functions.Function1<? super A, java.lang.Boolean>);
    Code:
       0: aload_0
       1: ldc           #177                // String xs
       3: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #185                // String p
       9: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: aload_1
      14: iconst_0
      15: invokestatic  #189                // Method findFirst$loop:([Ljava/lang/Object;Lkotlin/jvm/functions/Function1;I)I
      18: ireturn

  public static final <T> java.util.List<T> getTail(java.util.List<? extends T>);
    Code:
       0: aload_0
       1: ldc           #195                // String <this>
       3: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #197                // class java/lang/Iterable
      10: iconst_1
      11: invokestatic  #201                // Method kotlin/collections/CollectionsKt.drop:(Ljava/lang/Iterable;I)Ljava/util/List;
      14: areturn

  public static final <T> T getHead(java.util.List<? extends T>);
    Code:
       0: aload_0
       1: ldc           #195                // String <this>
       3: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokestatic  #209                // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
      10: areturn

  public static final <A> boolean isSorted(java.util.List<? extends A>, kotlin.jvm.functions.Function2<? super A, ? super A, java.lang.Boolean>);
    Code:
       0: aload_0
       1: ldc           #213                // String aa
       3: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #215                // String ordered
       9: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_1
      13: aload_0
      14: invokestatic  #217                // Method getHead:(Ljava/util/List;)Ljava/lang/Object;
      17: aload_0
      18: invokestatic  #219                // Method getTail:(Ljava/util/List;)Ljava/util/List;
      21: invokestatic  #223                // Method isSorted$loop$8:(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Ljava/util/List;)Z
      24: ireturn

  public static final <A, B, C> kotlin.jvm.functions.Function1<B, C> partiall(A, kotlin.jvm.functions.Function2<? super A, ? super B, ? extends C>);
    Code:
       0: aload_1
       1: ldc           #228                // String f
       3: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: aload_0
       8: invokedynamic #236,  0            // InvokeDynamic #6:invoke:(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;)Lkotlin/jvm/functions/Function1;
      13: areturn

  public static final <A, B, C> kotlin.jvm.functions.Function1<A, kotlin.jvm.functions.Function1<B, C>> curry(kotlin.jvm.functions.Function2<? super A, ? super B, ? extends C>);
    Code:
       0: aload_0
       1: ldc           #228                // String f
       3: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokedynamic #247,  0            // InvokeDynamic #7:invoke:(Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function1;
      12: areturn

  public static final <A, B, C> kotlin.jvm.functions.Function2<A, B, C> uncurry(kotlin.jvm.functions.Function1<? super A, ? extends kotlin.jvm.functions.Function1<? super B, ? extends C>>);
    Code:
       0: aload_0
       1: ldc           #228                // String f
       3: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokedynamic #255,  0            // InvokeDynamic #8:invoke:(Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function2;
      12: areturn

  public static final <A, B, C> kotlin.jvm.functions.Function1<A, C> compose(kotlin.jvm.functions.Function1<? super B, ? extends C>, kotlin.jvm.functions.Function1<? super A, ? extends B>);
    Code:
       0: aload_0
       1: ldc           #228                // String f
       3: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc_w         #260                // String g
      10: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      13: aload_0
      14: aload_1
      15: invokedynamic #267,  0            // InvokeDynamic #9:invoke:(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1;
      20: areturn

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #270                // Method main:()V
       3: return

  private static final boolean main$lambda$0(java.lang.String);
    Code:
       0: aload_0
       1: ldc_w         #274                // String it
       4: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       7: aload_0
       8: ldc           #35                 // String Phil
      10: invokestatic  #278                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      13: ireturn

  private static final boolean main$lambda$1(boolean);
    Code:
       0: iload_0
       1: ifne          8
       4: iconst_1
       5: goto          9
       8: iconst_0
       9: ireturn

  private static final boolean main$lambda$2(int, int);
    Code:
       0: iload_0
       1: iload_1
       2: if_icmpge     9
       5: iconst_1
       6: goto          10
       9: iconst_0
      10: ireturn

  private static final boolean main$lambda$3(java.lang.String, java.lang.String);
    Code:
       0: aload_0
       1: ldc_w         #283                // String x
       4: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       7: aload_1
       8: ldc_w         #284                // String y
      11: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      14: aload_0
      15: invokevirtual #288                // Method java/lang/String.length:()I
      18: aload_1
      19: invokevirtual #288                // Method java/lang/String.length:()I
      22: if_icmpge     29
      25: iconst_1
      26: goto          30
      29: iconst_0
      30: ireturn

  private static final char main$lambda$4(int, java.lang.String);
    Code:
       0: aload_1
       1: ldc_w         #290                // String s
       4: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       7: aload_1
       8: iload_0
       9: invokevirtual #294                // Method java/lang/String.charAt:(I)C
      12: ireturn

  private static final char main$lambda$6$lambda$5(int, java.lang.String);
    Code:
       0: aload_1
       1: ldc_w         #290                // String s
       4: invokestatic  #183                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       7: aload_1
       8: iload_0
       9: invokevirtual #294                // Method java/lang/String.charAt:(I)C
      12: ireturn

  private static final kotlin.jvm.functions.Function1 main$lambda$6(int);
    Code:
       0: iload_0
       1: invokedynamic #303,  0            // InvokeDynamic #10:invoke:(I)Lkotlin/jvm/functions/Function1;
       6: areturn

  private static final int factorial$go(int, int);
    Code:
       0: iload_0
       1: ifgt          8
       4: iload_1
       5: goto          23
       8: iload_0
       9: iconst_1
      10: isub
      11: istore_2
      12: iload_0
      13: iload_1
      14: imul
      15: istore_3
      16: iload_2
      17: istore_0
      18: iload_3
      19: istore_1
      20: goto          0
      23: ireturn

  private static final int fib$go$7(int);
    Code:
       0: iload_0
       1: iconst_1
       2: if_icmpgt     9
       5: iload_0
       6: goto          22
       9: iload_0
      10: iconst_1
      11: isub
      12: invokestatic  #173                // Method fib$go$7:(I)I
      15: iload_0
      16: iconst_2
      17: isub
      18: invokestatic  #173                // Method fib$go$7:(I)I
      21: iadd
      22: ireturn

  private static final <A> int findFirst$loop(A[], kotlin.jvm.functions.Function1<? super A, java.lang.Boolean>, int);
    Code:
       0: nop
       1: iload_2
       2: aload_0
       3: arraylength
       4: if_icmplt     11
       7: iconst_m1
       8: goto          40
      11: aload_1
      12: aload_0
      13: iload_2
      14: aaload
      15: invokeinterface #135,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
      20: checkcast     #63                 // class java/lang/Boolean
      23: invokevirtual #310                // Method java/lang/Boolean.booleanValue:()Z
      26: ifeq          33
      29: iload_2
      30: goto          40
      33: iload_2
      34: iconst_1
      35: iadd
      36: istore_2
      37: goto          0
      40: ireturn

  private static final <A> boolean isSorted$loop$8(kotlin.jvm.functions.Function2<? super A, ? super A, java.lang.Boolean>, A, java.util.List<? extends A>);
    Code:
       0: nop
       1: aload_1
       2: ifnonnull     9
       5: iconst_1
       6: goto          62
       9: aload_2
      10: invokeinterface #318,  1          // InterfaceMethod java/util/List.isEmpty:()Z
      15: ifeq          22
      18: iconst_1
      19: goto          62
      22: aload_0
      23: aload_1
      24: aload_2
      25: invokestatic  #217                // Method getHead:(Ljava/util/List;)Ljava/lang/Object;
      28: invokeinterface #162,  3          // InterfaceMethod kotlin/jvm/functions/Function2.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
      33: checkcast     #63                 // class java/lang/Boolean
      36: invokevirtual #310                // Method java/lang/Boolean.booleanValue:()Z
      39: ifeq          61
      42: aload_2
      43: invokestatic  #217                // Method getHead:(Ljava/util/List;)Ljava/lang/Object;
      46: astore_3
      47: aload_2
      48: invokestatic  #219                // Method getTail:(Ljava/util/List;)Ljava/util/List;
      51: astore        4
      53: aload_3
      54: astore_1
      55: aload         4
      57: astore_2
      58: goto          0
      61: iconst_0
      62: ireturn

  private static final java.lang.Object partiall$lambda$9(kotlin.jvm.functions.Function2, java.lang.Object, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: aload_2
       3: invokeinterface #162,  3          // InterfaceMethod kotlin/jvm/functions/Function2.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
       8: areturn

  private static final java.lang.Object curry$lambda$11$lambda$10(kotlin.jvm.functions.Function2, java.lang.Object, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: aload_2
       3: invokeinterface #162,  3          // InterfaceMethod kotlin/jvm/functions/Function2.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
       8: areturn

  private static final kotlin.jvm.functions.Function1 curry$lambda$11(kotlin.jvm.functions.Function2, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokedynamic #329,  0            // InvokeDynamic #11:invoke:(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;)Lkotlin/jvm/functions/Function1;
       7: areturn

  private static final java.lang.Object uncurry$lambda$12(kotlin.jvm.functions.Function1, java.lang.Object, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokeinterface #135,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
       7: checkcast     #133                // class kotlin/jvm/functions/Function1
      10: aload_2
      11: invokeinterface #135,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
      16: areturn

  private static final java.lang.Object compose$lambda$13(kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: aload_2
       3: invokeinterface #135,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
       8: invokeinterface #135,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
      13: areturn
}


package de.rieckpil.learning.fpbook.datatypes

sealed class Tree<out A> {

  companion object {

    fun <A> size(tree: Tree<A>): Int =
      when (tree) {
        is Leaf -> 1
        is Branch -> 1 + size(tree.left) + size(tree.right)
      }

    fun maximum(tree: Tree<Int>): Int =
      when (tree) {
        is Leaf -> tree.value
        is Branch -> maxOf(maximum(tree.left), maximum(tree.right))
      }

    fun <A> depth(tree: Tree<A>): Int =
      when (tree) {
        is Leaf -> 0
        is Branch -> 1 + maxOf(depth(tree.left), depth(tree.left))
      }

    fun <A, B> map(tree: Tree<A>, f: (A) -> B): Tree<B> =
      when (tree) {
        is Leaf -> Leaf(f(tree.value))
        is Branch -> Branch(map(tree.left, f), map(tree.right, f))
      }

    fun <A, B> fold(tree: Tree<A>, l: (A) -> B, f: (B, B) -> B): B =
      when (tree) {
        is Leaf -> l(tree.value)
        is Branch -> f(fold(tree.left, l, f), fold(tree.right, l, f))
      }

    fun <A> sizeFold(tree: Tree<A>): Int = fold(tree, { 1 }, { a, b -> a + b + 1 })
    fun <A> maximumFold(tree: Tree<Int>): Int = fold(tree, { it }, { a, b -> maxOf(a, b) })
    fun <A> depthFold(tree: Tree<A>): Int = fold(tree, { 0 }, { a, b -> 1 + maxOf(a, b) })
    fun <A, B> mapFold(tree: Tree<A>, f: (A) -> B): Tree<B> = fold(tree, { a: A -> Leaf(f(a)) }, { a: Tree<B>, b: Tree<B> -> Branch(a, b) })
  }

}

data class Leaf<A>(val value: A) : Tree<A>()

data class Branch<A>(val left: Tree<A>, val right: Tree<A>) : Tree<A>()

fun main() {

  // println(Tree.size(Branch(Branch(Leaf(1), Leaf(2)), Leaf(2))))
  // println(Tree.maximum(Branch(Branch(Leaf(4), Leaf(2)), Leaf(7))))
  // println(Tree.depth(Branch(Branch(Leaf(4), Leaf(2)), Leaf(7))))
  // println(Tree.map(Branch(Branch(Leaf(4), Leaf(2)), Leaf(7))) { it * it })

  println(Tree.sizeFold(Branch(Branch(Leaf(4), Leaf(2)), Leaf(7))))

}

Compiled from "FunctionalTreeDataStructure.kt"
public final class de.rieckpil.learning.fpbook.datatypes.FunctionalTreeDataStructureKt {
  public static final void main();
    Code:
       0: getstatic     #12                 // Field de/rieckpil/learning/fpbook/datatypes/Tree.Companion:Lde/rieckpil/learning/fpbook/datatypes/Tree$Companion;
       3: new           #14                 // class de/rieckpil/learning/fpbook/datatypes/Branch
       6: dup
       7: new           #14                 // class de/rieckpil/learning/fpbook/datatypes/Branch
      10: dup
      11: new           #16                 // class de/rieckpil/learning/fpbook/datatypes/Leaf
      14: dup
      15: iconst_4
      16: invokestatic  #22                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      19: invokespecial #26                 // Method de/rieckpil/learning/fpbook/datatypes/Leaf."<init>":(Ljava/lang/Object;)V
      22: checkcast     #8                  // class de/rieckpil/learning/fpbook/datatypes/Tree
      25: new           #16                 // class de/rieckpil/learning/fpbook/datatypes/Leaf
      28: dup
      29: iconst_2
      30: invokestatic  #22                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      33: invokespecial #26                 // Method de/rieckpil/learning/fpbook/datatypes/Leaf."<init>":(Ljava/lang/Object;)V
      36: checkcast     #8                  // class de/rieckpil/learning/fpbook/datatypes/Tree
      39: invokespecial #29                 // Method de/rieckpil/learning/fpbook/datatypes/Branch."<init>":(Lde/rieckpil/learning/fpbook/datatypes/Tree;Lde/rieckpil/learning/fpbook/datatypes/Tree;)V
      42: checkcast     #8                  // class de/rieckpil/learning/fpbook/datatypes/Tree
      45: new           #16                 // class de/rieckpil/learning/fpbook/datatypes/Leaf
      48: dup
      49: bipush        7
      51: invokestatic  #22                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      54: invokespecial #26                 // Method de/rieckpil/learning/fpbook/datatypes/Leaf."<init>":(Ljava/lang/Object;)V
      57: checkcast     #8                  // class de/rieckpil/learning/fpbook/datatypes/Tree
      60: invokespecial #29                 // Method de/rieckpil/learning/fpbook/datatypes/Branch."<init>":(Lde/rieckpil/learning/fpbook/datatypes/Tree;Lde/rieckpil/learning/fpbook/datatypes/Tree;)V
      63: checkcast     #8                  // class de/rieckpil/learning/fpbook/datatypes/Tree
      66: invokevirtual #35                 // Method de/rieckpil/learning/fpbook/datatypes/Tree$Companion.sizeFold:(Lde/rieckpil/learning/fpbook/datatypes/Tree;)I
      69: istore_0
      70: getstatic     #41                 // Field java/lang/System.out:Ljava/io/PrintStream;
      73: iload_0
      74: invokevirtual #47                 // Method java/io/PrintStream.println:(I)V
      77: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #50                 // Method main:()V
       3: return
}


package de.rieckpil.learning.fpbook.propertytesting

interface RNG {
  fun nextInt(): Pair<Int, RNG>
}

data class SimpleRNG(val seed: Long) : RNG {
  override fun nextInt(): Pair<Int, RNG> {
    val newSeed = (seed * 0x5DEECE66DL + 0xBL) and 0xFFFFFFFFFFFFL
    val nextRNG = SimpleRNG(newSeed)
    val n = (newSeed ushr 16).toInt()
    return Pair(n, nextRNG)
  }
}

fun nonNegativeInt(rng: RNG): Pair<Int, RNG> {
  val (i1, rng2) = rng.nextInt()
  return Pair(if (i1 < 0) -(i1 + 1) else i1, rng2)
}

fun nextBoolean(rng: RNG): Pair<Boolean, RNG> {
  val (i1, rng2) = rng.nextInt()
  return Pair(i1 >= 0, rng2)
}

fun double(rng: RNG): Pair<Double, RNG> {
  val (i, rng2) = nonNegativeInt(rng)
  return Pair(i / (Int.MAX_VALUE.toDouble() + 1), rng2)
}

data class State<S, out A>(val run: (S) -> Pair<A, S>) {

  companion object {
    fun <S, A> unit(a: A): State<S, A> =
      State { s: S -> Pair(a, s) }

    fun <S, A, B, C> map2(
      ra: State<S, A>,
      rb: State<S, B>,
      f: (A, B) -> C
    ): State<S, C> =
      ra.flatMap { a ->
        rb.map { b ->
          f(a, b)
        }
      }

    fun <S, A> sequence(
      fs: List<State<S, A>>
    ): State<S, List<A>> =
      fs.foldRight(unit(emptyList())) { f, acc ->
        map2(f, acc) { h, t -> listOf(h) + t }
      }
  }

  fun <B> map(f: (A) -> B): State<S, B> =
    flatMap { a -> unit<S, B>(f(a)) }

  fun <B> flatMap(f: (A) -> State<S, B>): State<S, B> =
    State { s: S ->
      val (a: A, s2: S) = this.run(s)
      f(a).run(s2)
    }
}

Compiled from "Boilerplate.kt"
public final class de.rieckpil.learning.fpbook.propertytesting.BoilerplateKt {
  public static final kotlin.Pair<java.lang.Integer, de.rieckpil.learning.fpbook.propertytesting.RNG> nonNegativeInt(de.rieckpil.learning.fpbook.propertytesting.RNG);
    Code:
       0: aload_0
       1: ldc           #10                 // String rng
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokeinterface #22,  1           // InterfaceMethod de/rieckpil/learning/fpbook/propertytesting/RNG.nextInt:()Lkotlin/Pair;
      12: astore_1
      13: aload_1
      14: invokevirtual #28                 // Method kotlin/Pair.component1:()Ljava/lang/Object;
      17: checkcast     #30                 // class java/lang/Number
      20: invokevirtual #34                 // Method java/lang/Number.intValue:()I
      23: istore_2
      24: aload_1
      25: invokevirtual #37                 // Method kotlin/Pair.component2:()Ljava/lang/Object;
      28: checkcast     #18                 // class de/rieckpil/learning/fpbook/propertytesting/RNG
      31: astore_3
      32: new           #24                 // class kotlin/Pair
      35: dup
      36: iload_2
      37: ifge          47
      40: iload_2
      41: iconst_1
      42: iadd
      43: ineg
      44: goto          48
      47: iload_2
      48: invokestatic  #43                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      51: aload_3
      52: invokespecial #47                 // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
      55: areturn

  public static final kotlin.Pair<java.lang.Boolean, de.rieckpil.learning.fpbook.propertytesting.RNG> nextBoolean(de.rieckpil.learning.fpbook.propertytesting.RNG);
    Code:
       0: aload_0
       1: ldc           #10                 // String rng
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokeinterface #22,  1           // InterfaceMethod de/rieckpil/learning/fpbook/propertytesting/RNG.nextInt:()Lkotlin/Pair;
      12: astore_1
      13: aload_1
      14: invokevirtual #28                 // Method kotlin/Pair.component1:()Ljava/lang/Object;
      17: checkcast     #30                 // class java/lang/Number
      20: invokevirtual #34                 // Method java/lang/Number.intValue:()I
      23: istore_2
      24: aload_1
      25: invokevirtual #37                 // Method kotlin/Pair.component2:()Ljava/lang/Object;
      28: checkcast     #18                 // class de/rieckpil/learning/fpbook/propertytesting/RNG
      31: astore_3
      32: new           #24                 // class kotlin/Pair
      35: dup
      36: iload_2
      37: iflt          44
      40: iconst_1
      41: goto          45
      44: iconst_0
      45: invokestatic  #58                 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
      48: aload_3
      49: invokespecial #47                 // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
      52: areturn

  public static final kotlin.Pair<java.lang.Double, de.rieckpil.learning.fpbook.propertytesting.RNG> double(de.rieckpil.learning.fpbook.propertytesting.RNG);
    Code:
       0: aload_0
       1: ldc           #10                 // String rng
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokestatic  #62                 // Method nonNegativeInt:(Lde/rieckpil/learning/fpbook/propertytesting/RNG;)Lkotlin/Pair;
      10: astore_1
      11: aload_1
      12: invokevirtual #28                 // Method kotlin/Pair.component1:()Ljava/lang/Object;
      15: checkcast     #30                 // class java/lang/Number
      18: invokevirtual #34                 // Method java/lang/Number.intValue:()I
      21: istore_2
      22: aload_1
      23: invokevirtual #37                 // Method kotlin/Pair.component2:()Ljava/lang/Object;
      26: checkcast     #18                 // class de/rieckpil/learning/fpbook/propertytesting/RNG
      29: astore_3
      30: new           #24                 // class kotlin/Pair
      33: dup
      34: iload_2
      35: i2d
      36: ldc2_w        #63                 // double 2.147483648E9d
      39: ddiv
      40: invokestatic  #69                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      43: aload_3
      44: invokespecial #47                 // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
      47: areturn
}