Skip to content

Instantly share code, notes, and snippets.

@matfournier
Last active October 30, 2018 05:17
Show Gist options
  • Save matfournier/805489b25e111ab4090d18a45817bcce to your computer and use it in GitHub Desktop.
Save matfournier/805489b25e111ab4090d18a45817bcce to your computer and use it in GitHub Desktop.
Playing with haskell to solve a scala problem
-- so I have a problem where I had some ADT. I need to produce some FinalResult at a
-- much later time where the ADT is some input on the way to getting this final result
-- Each member of the ADT needs some different piece of missing information required to produce the final result
-- at some point we end up with this missing information
-- to get the final result, pattern match on the ADT and provide the correct bit of missing info
-- leads to a lot of pattern matching in Scala.
-- Typeclass looks nicer but feels just like moving the pattern match around
-- and looks 100x uglier in scala due to cruft/implicits
-- alternatives?
-- in my scala code I don't necessarily have the MissingInformation all bundled up into some type
-- I have a class that has a bunch of info (some of which is most of the MissingInformation) and one of the ADTs
-- and some fn call that provides the remaining bit of MissingInformation needed to combine it all together to
-- get the final result.
-- trying to lean less on pattern matching but don't see a solution?
data FinalResult = FinalResult Int deriving Show
data Inputs = Input1 Int
| Input2 Int Int
| Input3 String
deriving Show
-- say Input 1 needs some later String to be provided to get to FinalResult
-- Input 2 needs some later () to be provided to get to FinalResult
-- Input 3 needs some Int to be provided to get to FinalResult
data MissingInformation = MissingInformation { s :: String
, i :: Int}
-- straight up pattern matching
inputToFinal :: Inputs -> MissingInformation -> FinalResult
inputToFinal (Input1 i) (MissingInformation s _) = FinalResult $ i + read s
inputToFinal (Input2 i j) (MissingInformation _ _) = FinalResult $ i + j
inputToFinal (Input3 s) (MissingInformation _ i) = FinalResult $ read s + i
-- via typeclasses, but isn't this just shifting the pattern match?
-- this is all fine but is super heavy on the pattern matching (it looks MUCH worse in scala)
-- the type class soln helps, but feels like it just moves the pattern match somewhere else
-- and is 10x as ugly in Scala w/ implicits
class GivesFinalResult a where
invoke :: a -> MissingInformation -> FinalResult
instance GivesFinalResult Inputs where
invoke (Input1 i) (MissingInformation s _) = FinalResult $ i + read s
invoke (Input2 i j)(MissingInformation _ _) = FinalResult $ i + j
invoke (Input3 s)(MissingInformation _ i) = FinalResult $ read s + i
-- constrain the type here
input2Final :: (GivesFinalResult i) => i -> MissingInformation -> FinalResult
input2Final inputs missing = invoke inputs missing
-- q: how to avoid explosion of types if new Inputs are added
-- esp if they also need new MissingInformation
-- followup q: what if Inputs was 30 types? How would you do this differently
-- q: what if Inputs was several things?
-- a: I think... who cares as long as they implement GivesFinalResult
-- q: alternatives to this?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment