Skip to content

Instantly share code, notes, and snippets.

@Aster89
Created March 7, 2021 11:14
Show Gist options
  • Save Aster89/b2769814993cec1608e1e6e815b112de to your computer and use it in GitHub Desktop.
Save Aster89/b2769814993cec1608e1e6e815b112de to your computer and use it in GitHub Desktop.
simple haskell program
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
@leftaroundabout
Copy link

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 -> ....

@Aster89
Copy link
Author

Aster89 commented Mar 7, 2021

(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?

@leftaroundabout
Copy link

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).

@Aster89
Copy link
Author

Aster89 commented Mar 7, 2021

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment