-
-
Save Aster89/b2769814993cec1608e1e6e815b112de to your computer and use it in GitHub Desktop.
data Dialog = WinDialog { render :: IO (), click :: IO () } | |
| MacDialog { render :: IO (), click :: IO () } | |
| LnxDialog { render :: IO (), click :: IO () } | |
askForConfirmThenError :: IO () | |
askForConfirmThenError = do | |
print "Are you sure? [y/n]" | |
ans <- getLine | |
if ans == "n" | |
then print "Ok, (not) done" | |
else error "Ooops, I'm bugged" | |
askForMoneyThanDo :: IO () | |
askForMoneyThanDo = do | |
print "Pay first..." | |
ans <- getLine | |
let money = read ans :: Int | |
if money < 10 | |
then error "No way!" | |
else print "Ok, done." | |
createDialogFor :: String -> Dialog | |
createDialogFor "w" = WinDialog (print "Hello, I'm a Win dialog") askForConfirmThenError | |
createDialogFor "m" = MacDialog (print "Hello, I'm a Mac dialog") askForMoneyThanDo | |
createDialogFor "l" = LnxDialog (print "Hello, I'm a Lnx dialog") (print "the job is done") | |
createDialogFor _ = error "Error: unknown OS." | |
main :: IO () | |
main = do | |
print "Which os? [w/m/l]" | |
os <- getLine -- for simplicity, read from keyboard instead of from system | |
let dialog = createDialogFor os | |
render dialog | |
click dialog |
Maybe you don't even need to store targetOS
at all.
Alternatively, it could actually make sense to have the OS distinction on the type level. This can be done with -XDataKinds
:
{-# LANGUAGE DataKinds, KindSignatures #-}
data OS = Win | Mac | Linux
data Dialog (os :: OS) = Dialog { render :: IO (), click :: IO () }
This way you can have both platform-independent functions Dialog os -> ...
, as well as platform-specific ones Dialog 'Linux -> ...
.
(This is an answer to your first comment. I'll read the other two now, as I've just refreshed the page.)
I see... So in your solution having a targetOS :: OS
member, which is not used in this simple example, would serve the same purpose as the separate constructors in my original code, i.e. querying what OS the button is rendered for, right?
Yes, both designs are isomorphic but mine allows writing code that can call the “methods” without caring about what OS we're on (like you could do in an OO language on an object of abstract base class).
Thank you very much for your comments.
As regards the second to last comment of yours (about distinguishing the OS on the type level), I think probably it's a bit to early for me to really understand it. However, as a future reference for myself, would you mind showing me how that would translate in my example, if we say, for instance, that render
is platform-specific and click
is not?
I see no good reason to have separate constructors for
WinDialog
,MacDialog
andLnxDialog
here.Why not instead