In Io, you can set the execution context using do:
Http := Object clone
Http get := method(uri, ("<GET request to " .. uri .. ">") println)
Http delete := method(uri, ("<DELETE request to " .. uri .. ">") println)
Database := Object clone
Database insert := method(table, data, ("<insert data to " .. table .. ">") println)
Database delete := method(table, id, ("<delete " .. id .. " from " .. table .. ">") println)
Http do(
get("http://example.com/")
delete("http://example.com/something")
)
Database do(
insert("cats", list("Phil", "gray"))
delete("cats", 12)
)
(Ruby has a similar feature with Object#instance_exec, but its object model is a bit more complicated.)
In effect, this gives you a temporary namespace, which is nice for writing domain specific languages. Is there a technique to achieve a similar effect (a temporary namespace) in Haskell?
For example, something like: (Not necessarily exactly like this, but something with similarly succinct syntax.)
main = do
http $ do
get "http://example.com/"
delete "http://example.com/something"
database $ do
insert "cats" ["Phil", "gray"]
delete "cats" 12
Notice that the two deletes are completely different functions. I’d prefer to avoid writing things like H.delete and D.delete, because that would get messy quick. I realize that this could be avoided by renaming that database version to, for example, deleteFrom, but I don’t want to.
“That is crazy dynamic stuff. You could never do that in a static language…”
“that is crazy. No way it works”
you should probably not actually do things this way. But if that is really what you want, implicit parameters are probably the most elegant way to get it
applicative’s RecordWildCard solution is in some sense better than this since it takes less code to set up, and involves a much smaller extension to the language. Furthermore it is very similar to using “open” directives in languages with proper module systems, or “using namespace” commands in languages with flexible name spacing (Haskell has neither). The implicit parameter solution captures something similar to the semantics of dynamic languages. In particular, using it you can call a function that uses the implicit arguments, and not have to worry about manually passing the environment.
You can also simulate implicit parameters here with a ReaderT or something like it. Although (for various reasons), that is not very compositional if you want to stay in Haskell 98.