I am writing a program with several functions that take the same arguments. Here is a somewhat contrived example for simplicity:
buildPhotoFileName time word stamp = show word ++ "-" ++ show time ++ show stamp
buildAudioFileName time word = show word ++ "-" ++ show time ++ ".mp3"
buildDirectoryName time word = show word ++ "_" ++ show time
Say I am looping over a resource from IO to get the time
and word
parameters at runtime. In this loop, I need to join the results of the above functions for further processing so I do this:
let photo = buildPhotoFileName time word stamp
audio = buildAudioFileName time word
dir = buildDirectoryName time word
in ....
This seems like a violation of "Don't Repeat Yourself" principle. If down the road I find I would like to change word
to a function taking word
, I might make a new binding at the beginning of let
expression like so:
let wrd = processWord word
photo = buildPhotoFileName time wrd stamp
audio = buildAudioFileName time wrd
dir = buildDirectoryName time wrd
in ....
and would have to change each time I wrote word
to wrd
, leading to bugs if I remember to change some function calls, but not the others.
In OOP, I would solve this by putting the above functions in a class whose constructor would take time
and word
as arguments. The instantiated object would essentially be the three functions curried to time
and word
. If I wanted to then make sure that the functions receive processWord word
instead of word
as an "argument", I could call processWord
in the constructor.
What is a better way to do this that would be more suited to Functional Programming and Haskell?
Since you say you're ready to create an OO-wrapper-class just for that, I assume you're open to changing your functions. Following is a function producting a tuple of all three results you wanted:
buildFileNames time word stamp =
( show word ++ "-" ++ show time ++ show stamp,
show word ++ "-" ++ show time ++ ".mp3",
show word ++ "_" ++ show time )
You'll be able to use it like so:
let wrd = processWord word
(photo, audio, dir) = buildFileNames time wrd stamp
in ....
And if you don't need any of the results, you can just skip them like so:
let wrd = processWord word
(_, audio, _) = buildFileNames time wrd stamp
in ....
It's worth noting that you don't have to worry about Haskell wasting resources on computing values you don't use, since it's lazy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With