data classStudent(valname:String,valfives:Int,valtens:Int,valtwenties:Int)privatevalStudent.total:Intget()=fives*5+tens*10+twenties*20sealedclassStudentAccumulator{abstractvalmoney:Int}objectEmpty:StudentAccumulator(){overridevalmoney=0}data classErrorFound(valmessage:String):StudentAccumulator(){overridevalmoney=0}data classMaxFound(valname:String,overridevalmoney:Int):StudentAccumulator()data classTieFound(overridevalmoney:Int):StudentAccumulator()fungenerateStudentFolder(compareFn:(StudentAccumulator,Student)->Int)={acc:StudentAccumulator,student:Student->when(acc){isErrorFound->accisEmpty->MaxFound(student.name,student.total)isMaxFound->acc.consider(student,compareFn)isTieFound->acc.consider(student,compareFn)}}funMaxFound.consider(student:Student,compareFn:(StudentAccumulator,Student)->Int)=when(compareFn(this,student)){-1->MaxFound(student.name,student.total)0->TieFound(student.total)else->this}funTieFound.consider(student:Student,compareFn:(StudentAccumulator,Student)->Int)=when(compareFn(this,student)){-1->MaxFound(student.name,student.total)0->ErrorFound("More than one maximum")else->this}funIterable<Student>.findMax()=fold(EmptyasStudentAccumulator,generateStudentFolder{a,b->a.money.compareTo(b.total)})funIterable<Student>.findMaxName():String{returnwhen(valresult=findMax()){isErrorFound->throwError(result.message)isEmpty->throwError("No max found")isMaxFound->result.nameisTieFound->"all"}}funmain(){valstudentsA=listOf(Student("a",1,1,1))println(studentsA.findMaxName())valstudentsB=listOf(Student("a",1,1,1),Student("b",1,1,1))println(studentsB.findMaxName())valstudentsC=listOf(Student("a",1,1,1),Student("c",2,1,1),Student("b",1,1,1))println(studentsC.findMaxName())}
It's typesafe, and we could change the comparator out if we wanted to. A little kludgey in the fold section (I should probably involve Option to avoid people accidentally calling money on the Empty and Error types. 🤷♀️
While I love the sealed class idea in Kotlin, type erasure and lack of true pattern matching really hampers the readability. If I was able to rely on StudentAccumulator auto-casting to its internal types, then I could remove a when statement that just dispatches out to the same overloaded call with the proper type.
Ok, I fixed it. It's not too much uglier with proper Option protection...
importarrow.core.Optionimportarrow.core.getOrElsedata classStudent(valname:String,valfives:Int,valtens:Int,valtwenties:Int)privatevalStudent.total:Intget()=fives*5+tens*10+twenties*20sealedclassStudentAccumulator{abstractvalmoney:Option<Int>}objectEmpty:StudentAccumulator(){overridevalmoney=Option.empty<Int>()}data classErrorFound(valmessage:String):StudentAccumulator(){overridevalmoney=Option.empty<Int>()}data classMaxFound(valname:String,overridevalmoney:Option<Int>):StudentAccumulator(){constructor(student:Student):this(student.name,Option.just(student.total))}data classTieFound(overridevalmoney:Option<Int>):StudentAccumulator(){constructor(student:Student):this(Option.just(student.total))}fungenerateStudentFolder(compareFn:(StudentAccumulator,Student)->Option<Int>)={acc:StudentAccumulator,student:Student->when(acc){isErrorFound->accisEmpty->MaxFound(student)isMaxFound->acc.consider(student,compareFn)isTieFound->acc.consider(student,compareFn)}}funMaxFound.consider(student:Student,compareFn:(StudentAccumulator,Student)->Option<Int>)=compareFn(this,student).map{result->when(result){-1->MaxFound(student)0->TieFound(student)else->this}}.getOrElse{ErrorFound("Bad comparison.")}funTieFound.consider(student:Student,compareFn:(StudentAccumulator,Student)->Option<Int>)=compareFn(this,student).map{result->when(result){-1->MaxFound(student)0->ErrorFound("More than one maximum")else->this}}.getOrElse{ErrorFound("Bad comparison.")}funIterable<Student>.findMax()=fold(EmptyasStudentAccumulator,generateStudentFolder{a,b->a.money.map{it.compareTo(b.total)}})funIterable<Student>.findMaxName():String{returnwhen(valresult=findMax()){isErrorFound->throwError(result.message)isEmpty->throwError("No max found")isMaxFound->result.nameisTieFound->"all"}}
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Ridiculously over-engineered Kotlin version:
It's typesafe, and we could change the comparator out if we wanted to. A little kludgey in the fold section (I should probably involve Option to avoid people accidentally calling money on the
Empty
andError
types. 🤷♀️While I love the
sealed class
idea in Kotlin, type erasure and lack of true pattern matching really hampers the readability. If I was able to rely onStudentAccumulator
auto-casting to its internal types, then I could remove a when statement that just dispatches out to the same overloaded call with the proper type.Ok, I fixed it. It's not too much uglier with proper Option protection...