{"id":20324375,"url":"https://github.com/oniani/miniframe","last_synced_at":"2025-03-04T10:21:21.974Z","repository":{"id":112156442,"uuid":"162125673","full_name":"oniani/miniframe","owner":"oniani","description":"Minimal data frames with relational algebra","archived":false,"fork":false,"pushed_at":"2021-01-03T12:54:18.000Z","size":596,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-02T10:08:12.328Z","etag":null,"topics":["data","dataframe-library","haskell","haskell-library","library"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oniani.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-17T12:14:41.000Z","updated_at":"2021-01-03T12:54:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"f1bcfd2a-a86f-4077-9ae0-043cb2516ca4","html_url":"https://github.com/oniani/miniframe","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oniani%2Fminiframe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oniani%2Fminiframe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oniani%2Fminiframe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oniani%2Fminiframe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oniani","download_url":"https://codeload.github.com/oniani/miniframe/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241827453,"owners_count":20026689,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data","dataframe-library","haskell","haskell-library","library"],"created_at":"2024-11-14T19:33:46.177Z","updated_at":"2025-03-04T10:21:21.953Z","avatar_url":"https://github.com/oniani.png","language":"Haskell","readme":"# MiniFrame\n\nMiniFrame provides a simple and user-friendly interface for working\nwith datasets in a tabular format. The idea of a miniframe comes from\nprogramming language R's `data.frame` object. MiniFrame is just a very\nstripped down version of R's `data.frame`. It provides just enough power\nand flexibility to conveniently explore the data. The function names as\nwell as their functionalities are so simple that even those who are not\nfamiliar with Haskell can easily use this package for their convenience.\n\nFor the sake of simplicity, everything in a miniframe is of the type\n`String` (the same as `[Char]`). Yet, this does not make interacting\nwith miniframes very inconvenient, nor does it limit its flexibility.\nA separate section in the documentation will be dedicated to this issue.\nMiniFrame heavily utilizes Haskell's `List` data type meaning that\neverything within miniframes including the fundamental data types can\nbe manipulated directly using built-in list functions such as `map`,\n`concatMap`, `foldl`, `foldr`, `scanl`, `scanr`, and so forth.\n\n\u003e NOTE: The PDF version of this documentation is available [here](./README.pdf).\n\n## Documentation\n\n- [Data types](#data-types)\n- [Construction](#construction)\n- [Accessing the data](#accessing-the-data)\n- [Counting the dimensions](#counting-the-dimensions)\n- [Modifications](#modifications)\n- [Removal](#removal)\n- [Pretty-printing](#pretty-printing)\n- [Additional operations](#additional-operations)\n- [Type conversion and numeric computation](#type-conversion-and-numeric-computation)\n- [Relational Algebra](#relational-algebra)\n- [Leveraging Haskell's built-in goodness](#leveraging-haskells-built-in-goodness)\n- [Installation](#installation)\n\nThose who want to take a look at Haddock-generated documentation,\njump to this [link](https://www.davidoniani.com//miniframe/).\nNote that the library is not well-documented on Haddock.\n\n### Data types\n\nMiniFrame has one fundamental data type, it is called `MiniFrame`.\nIts definition is shown below.\n\n```haskell\ndata MiniFrame = MiniFrame\n    { name   :: !Name\n    , header :: !Header\n    , rows   :: ![Row]\n    } deriving (Eq, Show)\n```\n\nMost of the functions operate on this data type. As it can be seen above,\nthere are auxiliary types, which are defined as follows:\n\n```haskell\ntype Index  = Int\ntype Name   = String\ntype Header = [Name]\ntype Row    = [String]\ntype Column = [String]\n```\n\nNote that the user does not need to be familiar with these types other\nthan knowing the fact that types `Header`, `Row`, and `Column` are just\nthe lists of the type `[String]`. These facts make it super simple\nto navigate through and manipulate the dataset as well as to perform\nnumeric computations.\n\n### Construction\n\n| Function      | Description               | Signature                                 |\n| ------------- | ------------------------- | ----------------------------------------- |\n| `fromSample`  | construct out of a sample | `MiniFrame`                               |\n| `fromNull`    | construct out of nothing  | `MiniFrame`                               |\n| `fromRows`    | construct out of rows     | `Name -\u003e Header -\u003e [Row] -\u003e MiniFrame`    |\n| `fromColumns` | construct out of columns  | `Name -\u003e Header -\u003e [Column] -\u003e MiniFrame` |\n| `fromCSV`     | construct out of CSV file | `String -\u003e IO MiniFrame`                  |\n\n**NOTE #1: Do not let names `fromSample` and `fromNull` deceive you.\nThe only thing these two functions do is a construction of a miniframe\nfrom a sample name, header, and rows and from nothing (resulting in an\nempty miniframe). Just for consistency, all these functions have a prefix\n`from`.**\n\n**NOTE #2: These are recommended ways (A.K.A. _smart_ constructors) to\nbuild a MiniFrame. Though, one could also use the `MiniFrame` data type\nconstructor to build it, but in this case, the error-handling will be left\nfor the user (:.**\n\nExample usage:\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO ()\nmain = do\n    -- A sample miniframe\n    let smf = fromSample\n\n    -- A null miniframe\n    let nmf = fromNull\n\n    -- Constructing a miniframe from rows\n    let rs = [ [\"Bianca\" , \"21\", \"Apple\" ]\n             , [\"Brian\"  , \"20\", \"Orange\"]\n             , [\"Bethany\", \"19\", \"Banana\"]\n             ]\n\n    let frmf = fromRows \"Favorite fruits\" [\"Name\", \"Age\", \"Favorite Fruit\"] rs\n\n    -- Constructing a miniframe from columns\n    let cs = [ [\"Walter\", \"John\", \"Eric\"]\n             , [\"500\"   , \"700\" , \"600\" ]\n             , [\"18\"    , \"20\"  , \"19\"  ]\n             ]\n\n    let fcmf = fromColumns \"Game scores\" [\"Player\", \"Score\", \"Age\"] cs\n\n    -- Constructing a miniframe from CSV file\n    mf \u003c- fromCSV \"schools.csv\"\n\n    return ()\n```\n\n### Accessing the data\n\n| Function    | Description     | Signature               |\n| ----------- | --------------- | ----------------------- |\n| `nameOf`    | get the name    | `MiniFrame -\u003e Name`     |\n| `headerOf`  | get the header  | `MiniFrame -\u003e Header`   |\n| `rowsOf`    | get the rows    | `MiniFrame -\u003e [Row]`    |\n| `columnsOf` | get the columns | `MiniFrame -\u003e [Column]` |\n| `headOf`    | get the head    | `MiniFrame -\u003e Row`      |\n| `tailOf`    | get the tail    | `MiniFrame -\u003e [Row]`    |\n\nExample usage:\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO ()\nmain = do\n    let n  = nameOf    fromSample  -- Get the name\n    let h  = headerOf  fromSample  -- Get the header\n    let rs = rowsOf    fromSample  -- Get the rows\n    let cs = columnsOf fromSample  -- Get the columns\n    let ho = headOf    fromSample  -- Get the head\n    let to = tailOf    fromSample  -- Get the tail\n\n    return ()\n```\n\n### Counting the dimensions\n\n| Function     | Description               | Signature          |\n| ------------ | ------------------------- | ------------------ |\n| `rowsNum`    | get the number of rows    | `MiniFrame -\u003e Int` |\n| `columnsNum` | get the number of columns | `MiniFrame -\u003e Int` |\n| `entriesNum` | get the number of cells   | `MiniFrame -\u003e Int` |\n\nExample usage:\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO ()\nmain = do\n    let rsn = rowsNum    fromSample  -- Number of rows\n    let csn = columnsNum fromSample  -- Number of columns\n    let esn = entriesNum fromSample  -- Number of cells\n\n    return ()\n```\n\n### Modifications\n\n| Function        | Description                   | Signature                                           |\n| --------------- | ----------------------------- | --------------------------------------------------- |\n| `prependRow`    | add a row to the beginning    | `Row -\u003e MiniFrame -\u003e MiniFrame`                     |\n| `prependColumn` | add a column to the beginning | `Name -\u003e Column -\u003e MiniFrame -\u003e MiniFrame`          |\n| `appendRow`     | add a row to the end          | `Row -\u003e MiniFrame -\u003e MiniFrame`                     |\n| `appendColumn`  | add a column to the end       | `Name -\u003e Column -\u003e MiniFrame -\u003e MiniFrame`          |\n| `insertRow`     | add a row by given index      | `Index -\u003e Row -\u003e MiniFrame -\u003e MiniFrame`            |\n| `insertColumn`  | add a column by given index   | `Index -\u003e Name -\u003e Column -\u003e MiniFrame -\u003e MiniFrame` |\n| `renameMf`      | rename a miniframe            | `Name -\u003e MiniFrame -\u003e MiniFrame`                    |\n\nExample usage:\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO ()\nmain = do\n    let newRow    = map show [1..4]  -- New row\n    let newColumn = map show [1..8]  -- New column\n\n    let prs = prependRow           newRow    fromSample  -- Prepend a row\n    let ars = prependColumn \"Nums\" newColumn fromSample  -- Prepend a column\n\n    let ars = appendRow           newRow    fromSample  -- Appending a row\n    let acs = appendColumn \"Nums\" newColumn fromSample  -- Appending a column\n\n    let irs = insertRow    1        newRow    fromSample  -- Inserting a row\n    let ics = insertColumn 3 \"Nums\" newColumn fromSample  -- Inserting a column\n\n    let rmf = renameMf \"New Name\" fromSample  -- Rename miniframe\n\n    return ()\n```\n\n### Removal\n\n| Function             | Description             | Signature                         |\n| -------------------- | ----------------------- | --------------------------------- |\n| `removeRowByIndex`   | remove a row by index   | `Index -\u003e MiniFrame -\u003e MiniFrame` |\n| `removeColumnByName` | remove a column by name | `Name -\u003e MiniFrame -\u003e MiniFrame`  |\n\nExample usage:\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO ()\nmain = do\n    let rrs = removeRowByIndex   2    fromSample  -- Remove a row by index\n    let rcs = removeColumnByName \"C4\" fromSample  -- Remove a column by name\n```\n\n### Pretty-printing\n\n| Function       | Description              | Signature                     |\n| -------------- | ------------------------ | ----------------------------- |\n| `printName`    | print the name           | `MiniFrame -\u003e IO ()`          |\n| `printHeader`  | print the header         | `MiniFrame -\u003e IO ()`          |\n| `printRow`     | print the row by index   | `Index -\u003e MiniFrame -\u003e IO ()` |\n| `printRows`    | print the rows           | `MiniFrame -\u003e IO ()`          |\n| `printColumn`  | print the column by name | `Name -\u003e MiniFrame -\u003e IO ()`  |\n| `printColumns` | print the columns        | `MiniFrame -\u003e IO ()`          |\n| `printMF`      | print the miniframe      | `MiniFrame -\u003e IO ()`          |\n\nExample usage:\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO\nmain = do\n    printName        fromSample  -- Pretty-print the name\n    printHeader      fromSample  -- Pretty-print the header\n    printRow    1    fromSample  -- Pretty-print the row by index\n    printRows        fromSample  -- Pretty-print all rows\n    printColumn \"C4\" fromSample  -- Pretty-print the column C4\n    printColumns     fromSample  -- Pretty-print all columns\n    printMF          fromSample  -- Pretty-print the miniframe\n\n    return ()\n```\n\n### Additional operations\n\n| Function        | Description             | Signature                      |\n| --------------- | ----------------------- | ------------------------------ |\n| `rowByIndex`    | get the row by index    | `Index -\u003e MiniFrame -\u003e Row`    |\n| `columnByName`  | get the column by name  | `Name -\u003e MiniFrame -\u003e Column`  |\n| `columnByIndex` | get the column by index | `Index -\u003e MiniFrame -\u003e Column` |\n\nExample usage:\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO ()\nmain = do\n    let rbi = rowByIndex    5    fromSample  -- Row by index\n    let cbn = columnByname  \"C3\" fromSample  -- Column by name\n    let cbi = columnByIndex 1    fromSample  -- Column by index\n\n    return ()\n```\n\n### Type conversion and numeric computation\n\n| Function       | Description                                                            | Signature                        |\n| -------------- | ---------------------------------------------------------------------- | -------------------------------- |\n| `toInt`        | Convert a column of string to a column of fixed-precision integers     | `Name -\u003e MiniFrame -\u003e [Int]`     |\n| `toDecimal`    | Convert a column of stings to a column of fixed-precision decimals     | `Name -\u003e MiniFrame -\u003e [Float]`   |\n| `toBigInt`     | Convert a column of string to a column of arbitrary precision integers | `Name -\u003e MiniFrame -\u003e [Integer]` |\n| `toBigDecimal` | Convert a column of stings to a column of arbitrary decimals           | `Name -\u003e MiniFrame -\u003e [Double]`  |\n\n**NOTE: Word \"arbitrary\" here refers to a size that can be handled by the machine.**\n\nExample usage:\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO ()\nmain = do\n    let mf = fromColumns\n\n           -- Name\n             \"MiniFrame\"\n\n             -- Header\n             [\"Name\",\"Quantity\",\"Total Spending\"]\n\n             -- Columns\n             [ [\"Paul\" , \"Ryan\", \"Kim\"  ]\n             , [\"10\"   , \"20\"  , \"30\"   ]\n             , [\"100.0\", \"200\" , \"300.0\"]\n             ]\n\n    -- Calculating the total quantity\n    let tq = sum $ toInt \"Quantity\" miniframe\n\n    -- Calculating the average number of dollars spent per person\n    let ad = sum (toDecimal \"Total Spending\" miniframe) / 3\n\n    -- Calculating the total quantity using arbitrary precision integers\n    let tqa = sum $ toBigInt \"Quantity\" miniframe\n\n    -- Calculating the average number of dollars spent per person\n    -- using arbitrary precision decimals\n    let ada = sum (toBigDecimal \"Total Spending\" miniframe) / 3\n\n    return ()\n```\n\n### Relational algebra\n\n| Function    | Description                    | Signature                                |\n| ----------- | ------------------------------ | ---------------------------------------- |\n| `union`     | union of two miniframes        | `MiniFrame -\u003e MiniFrame -\u003e MiniFrame`    |\n| `diff`      | difference of two miniframes   | `MiniFrame -\u003e MiniFrame -\u003e MiniFrame`    |\n| `intersect` | intersection of two miniframes | `MiniFrame -\u003e MiniFrame -\u003e MiniFrame`    |\n| `project`   | project a miniframe            | `[Name] -\u003e MiniFrame -\u003e MiniFrame`       |\n| `rename`    | rename a column                | `Name -\u003e Name -\u003e MiniFrame -\u003e MiniFrame` |\n\nExample usage:\n\n```haskell\n\nimport MiniFrame.Frames\nimport MiniFrame.Relational\n\nmain :: IO ()\nmain = do\n    let umf = fromSample  `union`     fromSample  -- Union\n    let dmf = fromSample  `diff`      fromSample  -- Difference\n    let imf = fromSample  `intersect` fromSample  -- Intersection\n    let pmf = project     [\"C2\",\"C4\"] fromSample  -- Projection\n    let cmf = fromColumns \"R1\" [\"C1\",\"C2\"] [[\"A\",\"B\",\"C\"],[\"1\",\"2\",\"3\"]]\n              `cartprod`\n              fromColumns \"R2\" [\"C3\",\"C4\"] [[\"4\",\"5\",\"6\"],[\"D\",\"E\",\"F\"]]\n    let rmf = rename      \"C1\" \"FC\"  fromSample   -- Rename\n\n    return ()\n```\n\n### Leveraging Haskell's built-in goodness\n\nRecall that miniframe is built on top of Haskell's built-in list\ndata type which is arguably the most powerful data type in Haskell.\nThis means that we can use the built-in list manipulation functions\ndirectly.\n\n```haskell\nimport MiniFrame.Frames\n\nmain :: IO ()\nmain = do\n    let mf = fromRows\n\n             -- Name\n             \"MiniFrame with numeric data\"\n\n             -- Header\n             [\"Product\",\"Company\",\"Value\"]\n\n             -- Rows\n             [ [\"FP toolkit\" , \"Haskell Enterprises\", \"1000000000000000000000.00\"]\n             , [\"OOP toolkit\", \"C++ Enterprises\"    , \"100000000000000000000.00\" ]\n             , [\"PP toolkit\" , \"C Enterprises\"      , \"10000000000000000000.00\"  ]\n             , [\"LP toolkit\" , \"Prolog Enterprises\" , \"1000000000000000000.00\"   ]\n             ]\n\n    -- Print out the average of all prices (notice the built-in sum function)\n    print $ sum $ toBigDecimal \"Value\" mf\n\n    -- Get the particular entry (\"Haskell Enterprises\" in this case)\n    -- notice Haskell's built-in head function\n    print $ head $ columnByName \"Company\" mf\n```\n\nUsing the built-in operations, however, does have its drawbacks such as\nno error messages if one messes up the structure of a miniframe. In other\nwords, one is on its own once the borders of MiniFrame are crossed.\n\n### Installation\n\nThe package can be installed via [Cabal](https://www.haskell.org/cabal/).\nRun the commands shown below to install the package.\n\n```sh\ngit clone https://github.com/oniani/miniframe.git\ncabal install\n```\n\n## License\n\n[MIT License](LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foniani%2Fminiframe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foniani%2Fminiframe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foniani%2Fminiframe/lists"}