3 ms·
This is pretty common in Haskell using the "recursion schemes" technique. The idea is to note that any recursive data type can be constructed by laying many "la
by tel 8y ago
This is pretty common in Haskell using the "recursion schemes" technique. The idea is to note that any recursive data type can be constructed by laying many "layers" down. For instance
data Json
= Str String
| Int Int
| Dict [(String, Json)]
has the "layer" type
data JsonLayer x
= StrL String
| IntL Int
| DictL [(String, x)]
You could also "layerize" the list in here which is what the author did with the DictVisitor, but I'll leave it as is for simplicity now.
We can recover the original type using the layers and the "type level fixed point operator"
newtype Fix f = Fix { unwrap :: f (Fix f) }
If you unwind this, it says
Fix JsonLayer = JsonLayer (Fix JsonLayer) = JsonLayer (JsonLayer (Fix JsonLayer)
= JsonLayer (JsonLayer (JsonLayer (...))
On the other hand, we can recursively consume values of `Fix JsonLayer` (and, equivalently, Json) with functions of the shape
type Alg f a = f a -> a
type JsonAlg a = JsonLayer a -> a
In other words, it tells us how to get a result from a single layer (where the recursive parts have already had their results computed). This is the Json visitor, though you can rewrite the type to be something more familiar
-- isomorphic to Alg JsonLayer a
data JsonVisitor a =
JsonVisitor
{ onStr :: String -> a
, onInt :: Int -> a
, onDict :: [(String, a)] -> a
}
You can write a function which consumes Fix'd data types using an appropriate Alg that is totally generic, or you can write a specific one for consuming Json using `Alg JsonLayer`
-- commonly seen as consume :: (JsonLayer a -> a) -> (Json -> a)
consume :: JsonVisitor a -> (Json -> a)
consume v (Str s) = onStr v s
consume v (Int i) = onInt v i
consume v pairs = onDict v $ map (\(n, json) -> (n, consume v json)) pairs
- dllthomas 8y ago> You could also "layerize" the list in here Is that the answer to "how do recursion schemes handle heterogenous layers"? I'd love to learn more.
- tel 8y agoThe general solution for heterogenous layers requires indexing the layers. The x type variable ends up having kind `Index -> *` for your index type Index.