0

Let's have some finite recursive datastructure in Haskell. Eg.

data Tree = Node Tree Tree | Nil

I need to be able to load such datastructure from Haskell to Python, change it and return it back to Haskell.

Is there some standard/elegant way how to do it without much pain? Eg. using some directory like objects?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Přemysl Šťastný
  • 1,676
  • 2
  • 18
  • 39
  • 1
    Depending on what you want to do with it, you may want to just have an opaque pointer on the Python side, and expose an API from Haskell to perform the operations Python needs (or vice versa -- opaque pointer to a Python object on the Haskell side with an API). The larger granularity you can make the operations in the API (i.e. the fewer times you need to cross the FFI barrier) the better, probably. – Daniel Wagner Feb 08 '22 at 19:50
  • @DanielWagner I would like to solve this [problem](https://stackoverflow.com/questions/71024653/python-how-to-update-yaml-file-without-loss-of-comments-and-formatting) using Megaparsec. I think the JSON solution is just enough for me. – Přemysl Šťastný Feb 09 '22 at 09:21
  • This question is currently opinion-based as phrased, and thus off-topic. Please revise the post to ask an *objective* question (specifically, asking for things like "elegant" or "best practice" or "more Pythonic" are off-topic because they are matters of opinion). – TylerH Feb 24 '22 at 15:20

1 Answers1

6

The easiest option is probably to go via JSON, because Haskell has easy support for saving data as JSON and Python can directly load it as dicts.

{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}

import GHC.Generics

import Data.Aeson
import Data.Aeson.TH

data Tree = Node Tree Tree | Nil
 deriving (Generic, FromJSON, ToJSON)

This generates rather awkward JSON though, like, Node (Node Nil Nil) Nil becomes

        "tag": "Node",
        "contents": [
            {
                "tag": "Node",
                "contents": [
                    {
                        "tag": "Nil"
                    },
                    {
                        "tag": "Nil"
                    }
                ]
            },
            {
                "tag": "Nil"
            }
        ]

It gets much more compact with

data TreeNode = Node { lSubtree, rSubtree :: Tree }
 deriving (Generic, FromJSON, ToJSON)

type Tree = Maybe TreeNode

where the equivalent Node (Just (Node Nothing Nothing)) Nothing is now saved as

        {
            "rSubtree": null,
            "lSubtree": {
                "rSubtree": null,
                "lSubtree": null
            }
        }
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319