Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

I\'ve seen this question but it doesn\'t help me because I\'m writing functional

ID: 639448 • Letter: I

Question

I've seen this question but it doesn't help me because I'm writing functional code (Standard ML) and the answers there are heavily focused towards OOP (the OP is advised to use the Facade pattern, to use inheritance, etc -- answers that are not relevant to an SML programmer).

In two separate, largely unrelated modules, Foo and Bar, I need to accomplish the same task: given functions equal and equals with the signatures:

val equal: t * t -> bool
val equals: t list * t list -> bool
make two new functions with the following signatures:

val equal': t * t -> t option
val equals': t list * t list -> t list option
Here, t stands for either Foo.t or Bar.t. The natural solution is to use a higher order function:

local
fun boolToOpt (comparison: ('a * 'a) -> bool) (left, right) =
    if comparison (left, right) then
      SOME left
    else
      NONE
in
val equal' = boolToOpt equal
val equals' = boolToOpt equals
end
I need to repeat exactly this code snippet in both modules.

Now, this is a tiny, minor implementation detail, and it would be a bad idea to let it be publicly visible from either Foo or Bar. At the same time, it seems too small -- and too tightly coupled to the two equal(s) functions -- to be factored out in to a module of its own. Maybe in another language, the equals' functionality would merit its own class, say, ComparisonDecorator, that overrides equal(s) to give me functions with the return type t option, but that's not an option here.

I run in to situations like these at least once per day. Is there a sane way to avoid just copy+pasting here?

Explanation / Answer

If you have absolutely no idea of a good abstraction for a module, put the function in a generic utility module, at least temporarily. And after you found several utility functions, you will probably identify some of them "belonging together". That will give you a hint for a common module name for these group of functions, so you can finally move them from the utility module into a module with a better name.

Just be careful not to let your utility module grow arbitrarily - from time to time, you have to clean up things there, otherwise you will reach a point where you don't know what's in there and what's not.

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote