I am new to Haskell, and I have been playing around with Arrows. I would like to write a tool that can programmatically "disassemble" a previously constructed Arrow. As a potential application, imagine a function that takes in an Arrow and returns a directed graph that represents all the concatenations, splits, fan-outs, etc.
E.g., (f &&& g) >>> h yields something like
----- f ----
---| |--- h -----
----- g ----
I initially thought I might be able to do this via pattern matching, as in the simple below (adapted from haskell.org Arrow tutorial), but it did not work.
module Main(main) where
import Control.Arrow
import Control.Category
import Prelude hiding (id, (.))
newtype SimpleFunc a b = SimpleFunc {runF :: (a -> b)}
instance Arrow SimpleFunc where
arr f = SimpleFunc f
first (SimpleFunc f) = SimpleFunc (mapFst f) where
mapFst g (a,b) = (g a, b)
second (SimpleFunc f) = SimpleFunc (mapSnd f) where
mapSnd g (a,b) = (a, g b)
instance Category SimpleFunc where
(SimpleFunc g) . (SimpleFunc f) = SimpleFunc (g . f)
id = arr id
f,g :: SimpleFunc Int Int
f = arr (\x -> x - 5)
g = arr (\x -> 3*x + 1)
h1 :: SimpleFunc Int Int
h1 = f >>> g
h2 :: SimpleFunc Int (Int, Int)
h2 = f &&& g
# It would be great if I something like this worked
is_split :: SimpleFunc a b -> Bool
is_split (a1 >>> a2) = False
is_split (a1 &&& a2) = True
....
is_split h2 -- evaluates to True
is_split h1 -- evaluates to False
All my attempts to do this by defining my own types (i.e., a parameterized type that includes types of constituent children as well) have also failed.
Is there some way to "pull apart" the components of an arrow once it has been constructed?
(->) is often called the "function arrow" or "function type constructor", and while it does have some special syntax, there's not that much special about it. It's essentially an infix type operator. Give it two types, and it gives you the type of functions between those types.
The Arrow (either (->) or MyArr ) is an abstraction of a computation. For a function b -> c , b is the input and c is the output. For a MyArr b c , b is the input and c is the output. 2) To actually run an arrow computation, you use a function specific to your arrow type.
You can make a free arrow, which is like a tree, so you can inspect its structure. Or lower it to underlying arrow. One example is in the other SO question: Useful operations on free arrows
The answer is going to be no in general, because fanout and composition and the other arrow operators are functions, not constructors. You can "pull apart", say, a tree, because composing trees out of other trees preserves the constructors used to perform the composition, and then Haskell can pattern-match on them. But there's no guarantee that composing arrows will preserve the fanouts and compositions used to perform the composition. It's like adding 2+3 and then trying to pull apart the 5 later.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With