One can use arrow notation in a language for hosting arrow notation module management and macros. Ideally, one would lift arrow notation to the host via a macro and then use it twice with different semantics: one for the internal DSL and again for the macro system.

The following is a Haskell proof of concept.

exampleModule :: ArrowLangModule
exampleModule = let
    -- Imports, declare all functions.
    f = require (Generator "f" 3 2)
    g = require (Generator "g" 2 1)
 
    -- Module definitions.
    def1 = arrowLang ["a","b","c"]
       $ Statement f ["a","b","c"] ["x","y"]
       $ Statement g ["a","y"] ["d"]
       $ Return ["x","y","d"]
 
    def2 = arrowLang ["x","y"]
       $ Statement def1 ["x","y","x"] ["u","v","w"]
       $ Statement f ["x","y","x"] ["u","v"]
       $ Return ["u"]
 
	-- Composition macro
    composition f g = arrowLang xs
       $ Statement f xs ys
       $ Statement g ys zs
       $ Return zs
      where
        -- would be better managed by explicit fresh name generation
        xs = take (source f) freshNames
        ys = take (target f) (drop (source f) freshNames)
        zs = take (target g) (drop (source f) (drop (target f) freshNames))

Note that the Haskell implementation of do-notation would not work as expected here.

example4 :: ArrowLang (Generator String)
example4 = do
    def1 <- ArrowLang ["a","b","c"]
       $ Statement (Generator "f" 3 2) ["a","b","c"] ["x","y"]
       $ Statement (Generator "g" 2 1) ["a","y"] ["d"]
       $ Return ["x","y","d"]
    def2 <- ArrowLang ["x","y"]
       $ Statement def1 ["x","y","x"] ["u","v","w"]
       $ Return ["u"]
    return def2

Instead of using the Kleisli category of the monad of arrow notation, we may want to implicitly use its category of algebras, which is cartesian, as a copy-discard category.

Tags: programming languages, arrow notation.