[
  {
    "path": ".gitignore",
    "content": ".stack-work\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: nix\nscript: nix-build release.nix\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "1.0.0\n\n* Initial release\n\n1.0.1\n\n* Added `diagrams` backend\n* Added variations on controls that accept starting values\n\n1.1\n\n* Reverse coordinate system for `diagrams` output.  The +y direction used to \n  point down and now it points up\n\n1.1.1\n\n* Add new controls for vertical and horizontal scales\n\n1.1.2\n\n* Expose `ui` function\n\n1.1.3\n\n* Support GHC 8.4\n\n1.1.4\n\n* Increase upper bounds on dependencies\n\n1.1.5\n\n* Increase upper bounds on dependencies\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015 Gabriella Gonzalez\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright notice,\n      this list of conditions and the following disclaimer in the documentation\n      and/or other materials provided with the distribution.\n    * Neither the name of Gabriella Gonzalez nor the names of other contributors\n      may be used to endorse or promote products derived from this software\n      without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# typed-spreadsheet v1.1.4\n\n`typed-spreadsheet` provides a typed and composable API for building\nspreadsheets.  This differs from traditional spreadsheets in a few important\nways:\n\n* you specify the relationship between inputs and outputs at compile time, not\n  runtime, so that the relationship can be type-checked\n* inputs of different types have different controls; for example, a `Bool` input\n  creates a checkbox and a `Double` input creates a spin button\n* you can only output a single value; you simulate multiple outputs by emitting\n  a tuple of values\n\n# Quick Start\n\nThis project includes two example executables that you can build and tweak to\ntest drive the library.  To clone, build, and run the executable just follow\nthese commands depending on your operating system:\n\n## OS X\n\n```bash\n$ # Installs the Gtk+ library\n$ brew install gtk\n\n$ # Creates a local copy of this repository\n$ git clone https://github.com/Gabriella439/Haskell-Typed-Spreadsheet-Library.git\n\n$ # Builds the executables\n$ stack build --stack-yaml=osx.yaml --install-ghc\n\n$ # Runs the text output example\n$ stack exec  --stack-yaml=osx.yaml typed-spreadsheet-example-text\n\n$ # Runs the graphical example\n$ stack exec  --stack-yaml=osx.yaml typed-spreadsheet-example-graphics\n```\n\n## Debian\n\nThese instructions will also probably work on other Linux distributions derived\nfrom Debian like Ubuntu or Mint:\n\n```bash\n$ # Install the Gtk+ 2.0 development headers\n$ sudo apt-get install libgtk2.0-dev\n\n$ # Creates a local copy of this repository\n$ git clone https://github.com/Gabriella439/Haskell-Typed-Spreadsheet-Library.git\n\n$ # Builds the executables\n$ stack build --install-ghc\n\n$ # Runs the text output example\n$ stack exec typed-spreadsheet-example-text\n\n$ # Runs the graphical example\n$ stack exec typed-spreadsheet-example-graphics\n```\n\n## Other operating systems\n\nIf you would like to contribute build instructions for other operating systems,\nplease submit a pull request.\n\n## Examples\n\nThe [executable code](https://github.com/Gabriella439/Haskell-Typed-Spreadsheet-Library/blob/master/exec/Text.hs)\nfor first example is short:\n\n```haskell\n{-# LANGUAGE ApplicativeDo     #-}\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Typed.Spreadsheet\n\nmain :: IO ()\nmain = textUI \"Example program\" $ do\n    a <- checkBox   \"a\"\n    b <- spinButton \"b\" 1\n    c <- spinButton \"c\" 0.1\n    d <- entry      \"d\"\n    return (display (a, b + c, d))\n```\n\n... and translates to a spreadsheet with all inputs on the left-hand side and\nthe output on the right-hand side:\n\n![](http://i.imgur.com/TTxgSwN.png)\n\nYou can also output updatable diagrams built using the `diagrams` library, such\nas [in this example](https://github.com/Gabriella439/Haskell-Typed-Spreadsheet-Library/blob/master/exec/Graphics.hs):\n\n```haskell\n{-# LANGUAGE ApplicativeDo     #-}\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Diagrams.Prelude\nimport Typed.Spreadsheet\n\ndata AColor = Red | Orange | Yellow | Green | Blue | Purple\n    deriving (Enum, Bounded, Show)\n\ntoColor :: AColor -> Colour Double\ntoColor Red    = red\ntoColor Orange = orange\ntoColor Yellow = yellow\ntoColor Green  = green\ntoColor Blue   = blue\ntoColor Purple = purple\n\nmain :: IO ()\nmain = graphicalUI \"Example program\" $ do\n    color <- radioButton      \"Color\"        Red [Orange .. Purple]\n    r     <- spinButtonAt 100 \"Radius\"       1\n    x     <- spinButton       \"X Coordinate\" 1\n    y     <- spinButton       \"Y Coordinate\" 1\n    return (circle r # fc (toColor color) # translate (r2 (x, y)))\n```\n\nThis produces a canvas that colors, resizes, and moves a circle in response to\nuser input:\n\n![](http://i.imgur.com/ddYoG46.png)\n\nTo learn more about the library, read the\n[documentation on Hackage](http://hackage.haskell.org/package/typed-spreadsheet/docs/Typed-Spreadsheet.html).\n\n# Additional examples\n\nMortgage calculator:\n\n```haskell\n{-# LANGUAGE ApplicativeDo     #-}\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Typed.Spreadsheet\n\nmain :: IO ()\nmain = textUI \"Mortgage payment\" $ do\n  mortgageAmount     <- spinButton \"Mortgage Amount\"          1000\n  numberOfYears      <- spinButton \"Number of years\"             1\n  yearlyInterestRate <- spinButton \"Yearly interest rate (%)\"    0.01\n  let n = truncate (numberOfYears * 12)\n  let i = yearlyInterestRate / 12 / 100\n  return (\"Monthly payment: $\" <> display (mortgageAmount * (i * (1 + i) ^ n) / ((1 + i) ^ n - 1)))\n```\n\nExample input and output:\n\n![Mortgage calculator program](http://i.imgur.com/nvRZ9HC.png)\n\nMad libs:\n\n```haskell\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Typed.Spreadsheet\n\nnoun = entry \"Noun\"\n\nverb = entry \"Verb\"\n\nadjective = entry \"Adjective\"\n\nexample =\n    \"I want to \" <> verb <> \" every \" <> noun <> \" because they are so \" <> adjective\n\nmain :: IO ()\nmain = textUI \"Mad libs\" example\n```\n\nExample input and output:\n\n![Mad libs program](http://i.imgur.com/k22An4Y.png)\n\nSinusoid plot:\n\n```haskell\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Diagrams.Prelude\nimport Typed.Spreadsheet\n\nmain :: IO ()\nmain = graphicalUI \"Example program\" $ do\n    amplitude <- spinButtonAt 50  \"Amplitude (Pixels)\"   0.1\n    frequency <- spinButtonAt 0.1 \"Frequency (Pixels⁻¹)\" 0.001\n    phase     <- spinButtonAt 90  \"Phase (Degrees)\"      1\n\n    let axes = arrowBetween (p2 (0, 0)) (p2 ( 100,    0))\n            <> arrowBetween (p2 (0, 0)) (p2 (-100,    0))\n            <> arrowBetween (p2 (0, 0)) (p2 (   0,  100))\n            <> arrowBetween (p2 (0, 0)) (p2 (   0, -100))\n\n    let f x = amplitude * cos (frequency * x + phase * pi / 180)\n\n    let points = map (\\x -> p2 (x, f x)) [-100, -99 .. 100]\n\n    return (strokeP (fromVertices points) <> axes)\n```\n\nExample input and output:\n\n![Sinusoid plot](http://i.imgur.com/ueF0w7U.png)\n\nFactor diagram:\n\n```haskell\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Diagrams.Prelude\nimport Diagrams.TwoD.Factorization (factorDiagram')\nimport Typed.Spreadsheet\n\nmain :: IO ()\nmain = graphicalUI \"Factor diagram\" $ do\n    x <- spinButtonAt 3 \"Factor #1\" 1\n    y <- spinButtonAt 3 \"Factor #2\" 1\n    z <- spinButtonAt 3 \"Factor #3\" 1\n    return (factorDiagram' [truncate x, truncate y, truncate z] # scale 10)\n```\n\nExample input and output:\n\n![Factor diagram](http://i.imgur.com/eMvMtKk.png)\n\n# How to contribute\n\nThe easiest way to contribute is to add new controls for user input.\n\nIf you are feeling particularly adventurous, you can work on adding a `diagrams`\noutput option instead of a text-based output.\n\n## Development Status\n\n[![Build Status](https://travis-ci.org/Gabriella439/Haskell-Typed-Spreadsheet-Library.png)](https://travis-ci.org/Gabriella439/Haskell-Typed-Spreadsheet-Library)\n\nThe high-level API for this library is unlikely to change.  I expect most of\nthe volatility early on will be in how much configuration for controls to expose\nto end users.  For example, controls could be generalized to permit stateful\noperations, but it's not clear if that additional complexity is worth it.\n\nThere might be new features added later such as `diagrams` output or new\ncontrols, but I expect those additions will not require any breaking changes to\nthe API.\n\n## LICENSE (BSD 3-Clause)\n\nCopyright (c) 2014 Gabriella Gonzalez\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright notice,\n      this list of conditions and the following disclaimer in the documentation\n      and/or other materials provided with the distribution.\n    * Neither the name of Gabriella Gonzalez nor the names of other contributors\n      may be used to endorse or promote products derived from this software\n      without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "Setup.hs",
    "content": "import Distribution.Simple\nmain = defaultMain\n"
  },
  {
    "path": "default.nix",
    "content": "let\n  fetchNixpkgs = import ./nix/fetchNixpkgs.nix;\n\n  nixpkgs = fetchNixpkgs {\n    rev = \"6a7dea9330c3d1f1f53610e753aada029eb8b86e\";\n\n    sha256 = \"0i8nf8szg27vnha8l22k9wwj3fyya6mf4b6g05fi1kyv3mmazhq7\";\n  };\n\n  readDirectory = import ./nix/readDirectory.nix;\n\n  config = {\n    packageOverrides = pkgs: {\n      haskellPackages = pkgs.haskellPackages.override {\n        overrides =\n          let\n            manualOverrides = haskellPackagesNew: haskellPackagesOld: {\n              typed-spreadsheet =\n                if pkgs.stdenv.isDarwin\n                then\n                  pkgs.haskell.lib.addBuildDepend\n                    haskellPackagesOld.typed-spreadsheet\n                    pkgs.darwin.apple_sdk.frameworks.Cocoa\n                else\n                  haskellPackagesOld.typed-spreadsheet;\n            };\n\n          in\n            pkgs.lib.composeExtensions (readDirectory ./nix) manualOverrides;\n      };\n    };\n  };\n\n  pkgs =\n    import nixpkgs { inherit config; };\n\nin\n  { inherit (pkgs.haskellPackages) typed-spreadsheet;\n\n    shell = (pkgs.haskell.lib.doBenchmark pkgs.haskellPackages.typed-spreadsheet).env;\n  }\n"
  },
  {
    "path": "exec/Cell.hs",
    "content": "{-# LANGUAGE ApplicativeDo     #-}\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Typed.Spreadsheet\n\nmain :: IO ()\nmain = cellUI \"Example program\" $ do\n    a <- checkBox   \"a\"\n    b <- spinButton \"b\" 1\n    c <- spinButton \"c\" 0.1\n    d <- entry      \"d\"\n    return\n        [ (\"a\"    , display  a     )\n        , (\"b + c\", display (b + c))\n        , (\"d\"    , display  d     )\n        ]\n"
  },
  {
    "path": "exec/Graphics.hs",
    "content": "{-# LANGUAGE ApplicativeDo     #-}\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Diagrams.Prelude\nimport Typed.Spreadsheet\n\ndata AColor = Red | Orange | Yellow | Green | Blue | Purple\n    deriving (Enum, Bounded, Show)\n\ntoColor :: AColor -> Colour Double\ntoColor Red    = red\ntoColor Orange = orange\ntoColor Yellow = yellow\ntoColor Green  = green\ntoColor Blue   = blue\ntoColor Purple = purple\n\nmain :: IO ()\nmain = graphicalUI \"Example program\" $ do\n    color <- radioButton                   \"Color\"        Red [Orange .. Purple]\n    r     <- spinButtonAt    100           \"Radius\"       1\n    x     <- hscaleWithRange (-200) 200 0  \"X Coordinate\" 10\n    y     <- vscaleWithRange (-200) 200 0  \"Y Coordinate\" 10\n    return (circle r # fc (toColor color) # translate (r2 (x, y)))\n"
  },
  {
    "path": "exec/Text.hs",
    "content": "{-# LANGUAGE ApplicativeDo     #-}\n{-# LANGUAGE OverloadedStrings #-}\n\nimport Typed.Spreadsheet\n\nmain :: IO ()\nmain = textUI \"Example program\" $ do\n    a <- checkBox   \"a\"\n    b <- spinButton \"b\" 1\n    c <- spinButton \"c\" 0.1\n    d <- entry      \"d\"\n    return (display (a, b + c, d))\n"
  },
  {
    "path": "nix/fetchNixpkgs.nix",
    "content": "{ rev                             # The Git revision of nixpkgs to fetch\n, sha256                          # The SHA256 hash of the unpacked archive\n, system ? builtins.currentSystem # This is overridable if necessary\n}:\n\nif (0 <= builtins.compareVersions builtins.nixVersion \"1.12\")\n\n# In Nix 1.12, we can just give a `sha256` to `builtins.fetchTarball`.\nthen (\n  builtins.fetchTarball {\n    url = \"https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz\";\n    inherit sha256;\n  })\n\n# This hack should at least work for Nix 1.11\nelse (\n  (rec {\n    tarball = import <nix/fetchurl.nix> {\n      url    = \"https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz\";\n      sha256 = null;\n    };\n\n    builtin-paths = import <nix/config.nix>;\n      \n    script = builtins.toFile \"nixpkgs-unpacker\" ''\n      \"$coreutils/mkdir\" \"$out\"\n      cd \"$out\"\n      \"$gzip\" --decompress < \"$tarball\" | \"$tar\" -x --strip-components=1\n    '';\n\n    nixpkgs = builtins.derivation ({\n      name = \"nixpkgs-${builtins.substring 0 6 rev}\";\n\n      builder = builtins.storePath builtin-paths.shell;\n\n      args = [ script ];\n\n      inherit tarball system;\n\n      tar       = builtins.storePath builtin-paths.tar;\n      gzip      = builtins.storePath builtin-paths.gzip;\n      coreutils = builtins.storePath builtin-paths.coreutils;\n    } // (if null == sha256 then { } else {\n      outputHashMode = \"recursive\";\n      outputHashAlgo = \"sha256\";\n      outputHash = sha256;\n    }));\n  }).nixpkgs)\n"
  },
  {
    "path": "nix/readDirectory.nix",
    "content": "directory:\n\nhaskellPackagesNew: haskellPackagesOld:\n  let\n    haskellPaths = builtins.attrNames (builtins.readDir directory);\n\n    toKeyVal = file: {\n      name  = builtins.replaceStrings [ \".nix\" ] [ \"\" ] file;\n\n      value = haskellPackagesNew.callPackage (directory + \"/${file}\") { };\n    };\n\n  in\n    builtins.listToAttrs (map toKeyVal haskellPaths)\n"
  },
  {
    "path": "nix/typed-spreadsheet.nix",
    "content": "{ mkDerivation, async, base, diagrams-cairo, diagrams-gtk\n, diagrams-lib, foldl, gtk, microlens, stdenv, stm, text\n, transformers\n}:\nmkDerivation {\n  pname = \"typed-spreadsheet\";\n  version = \"1.1.5\";\n  src = ./..;\n  isLibrary = true;\n  isExecutable = true;\n  libraryHaskellDepends = [\n    async base diagrams-cairo diagrams-gtk diagrams-lib foldl gtk\n    microlens stm text transformers\n  ];\n  executableHaskellDepends = [ base diagrams-lib text ];\n  description = \"Typed and composable spreadsheets\";\n  license = stdenv.lib.licenses.bsd3;\n}\n"
  },
  {
    "path": "nixpkgs.json",
    "content": "{\n  \"url\": \"https://github.com/NixOS/nixpkgs.git\",\n  \"rev\": \"09e191c22bbfad965a9b5469d5e0ac25b693036f\",\n  \"date\": \"2017-02-25T17:09:34+01:00\",\n  \"sha256\": \"1454ysw5gy52kb08v1wd2f6incp2ccmf79ni7kp2gmwrgsm3rrmj\"\n}\n"
  },
  {
    "path": "osx.yaml",
    "content": "resolver: lts-8.2\nextra-deps:\n- gtk-0.14.6\nflags:\n    gtk:\n        have-quartz-gtk: true  \n"
  },
  {
    "path": "release.nix",
    "content": "let\n  default = import ./default.nix;\n\nin\n  { inherit (default) typed-spreadsheet; }\n"
  },
  {
    "path": "shell.nix",
    "content": "(import ./default.nix).shell\n"
  },
  {
    "path": "src/Typed/Spreadsheet.hs",
    "content": "{-# LANGUAGE ExistentialQuantification  #-}\n{-# LANGUAGE RankNTypes                 #-}\n{-# LANGUAGE ApplicativeDo              #-}\n{-# LANGUAGE CPP              #-}\n\n-- | The following program:\n--\n-- > {-# LANGUAGE ApplicativeDo     #-}\n-- > {-# LANGUAGE OverloadedStrings #-}\n-- > \n-- > import Typed.Spreadsheet\n-- > \n-- > main :: IO ()\n-- > main = textUI \"Example program\" $ do\n-- >     a <- checkBox   \"a\"\n-- >     b <- spinButton \"b\" 1\n-- >     c <- spinButton \"c\" 0.1\n-- >     d <- entry      \"d\"\n-- >     return (display (a, b + c, d))\n--\n-- ... creates a user interface that looks like this:\n--\n-- <<http://i.imgur.com/xPifEtA.png User interface on startup>>\n--\n-- Every time you update a control on the left panel, the right panel updates\n-- in response:\n--\n-- <<http://i.imgur.com/TTxgSwN.png User interface after user input>>\n--\n-- This library also supports graphical output, like in the following program:\n--\n-- > {-# LANGUAGE ApplicativeDo     #-}\n-- > {-# LANGUAGE OverloadedStrings #-}\n-- > \n-- > import Diagrams.Prelude\n-- > import Typed.Spreadsheet\n-- > \n-- > data AColor = Red | Orange | Yellow | Green | Blue | Purple\n-- >     deriving (Enum, Bounded, Show)\n-- > \n-- > toColor :: AColor -> Colour Double\n-- > toColor Red    = red\n-- > toColor Orange = orange\n-- > toColor Yellow = yellow\n-- > toColor Green  = green\n-- > toColor Blue   = blue\n-- > toColor Purple = purple\n-- > \n-- > main :: IO ()\n-- > main = graphicalUI \"Example program\" $ do\n-- >     color <- radioButton      \"Color\"        Red [Orange .. Purple]\n-- >     r     <- spinButtonAt 100 \"Radius\"       1\n-- >     x     <- spinButton       \"X Coordinate\" 1\n-- >     y     <- spinButton       \"Y Coordinate\" 1\n-- >     return (circle r # fc (toColor color) # translate (r2 (x, y)))\n--\n-- This produces a canvas that colors, resizes, and moves a circle in response\n-- to user input:\n--\n-- <<http://i.imgur.com/ddYoG46.png Graphical user interface>>\n--\n-- The general workflow for this library is:\n--\n-- * You build primitive `Updatable` values using `checkBox`, `spinButton`,\n--   `entry`, or `radioButton`, each of which corresponds to a control on the\n--   left panel of the user interface\n-- * Combine `Updatable` values using @ApplicativeDo@ notation.  Composite values\n--   update whenever one of their substituent values update\n-- * You consume an @(`Updatable` `Text`)@ value using `textUI`, which displays\n--   the continuously updating value in the right panel of the user interface\n--\n-- You can get started quickly by cloning and building this project:\n--\n-- > $ git clone https://github.com/Gabriel439/Haskell-Typed-Spreadsheet-Library.git\n-- > $ stack build --install-ghc             # Builds the executable\n-- > $ stack exec typed-spreadsheet-example  # Runs the executable\n--\n-- ... or if you are using OS X, then build the project using:\n--\n-- > $ stack --stack-yaml=osx.yaml build --install-ghc\n--\n-- That project includes the code for the above examples in the @exec/@\n-- subdirectory.  Just modify that file and rebuild to play with the example.\n--\n-- NOTE: You must compile your program with the @-threaded@ flag.  The example\n-- project takes care of this.\n--\n-- See the \\\"Examples\\\" section at the bottom of this module for more examples.\n\nmodule Typed.Spreadsheet (\n    -- * Types\n      Updatable\n    , textUI\n    , cellUI\n    , graphicalUI\n    , ui\n\n    -- * Controls\n    , checkBox\n    , spinButton\n    , entry\n    , radioButton\n\n    -- * Controls with Defaults\n    , checkBoxAt\n    , spinButtonAt\n    , hscale\n    , hscaleAt\n    , hscaleWithRange\n    , vscale\n    , vscaleAt\n    , vscaleWithRange\n    , entryAt\n\n    -- * Utilities\n    , display\n\n    -- * Examples\n    -- $examples\n    ) where\n\nimport Control.Applicative\nimport Control.Concurrent.STM (STM)\nimport Control.Foldl (Fold(..))\nimport Control.Monad.IO.Class (liftIO)\nimport Data.String (IsString(..))\nimport Data.Text (Text)\nimport Diagrams.Backend.Cairo (Cairo)\nimport Diagrams.Prelude (Diagram, r2, reflectY, translate, (#))\nimport Lens.Micro (_Left, _Right)\nimport Graphics.UI.Gtk (AttrOp((:=)))\n\nimport qualified Control.Concurrent\nimport qualified Control.Concurrent.STM   as STM\nimport qualified Control.Concurrent.Async\nimport qualified Control.Foldl\nimport qualified Data.Text\nimport qualified Diagrams.Backend.Gtk\nimport qualified Graphics.UI.Gtk          as Gtk\n\ndata Cell a = forall e . Cell (IO (STM e, Fold e a))\n\ninstance Functor Cell where\n    fmap f (Cell m) = Cell (fmap (fmap (fmap f)) m)\n\ninstance Applicative Cell where\n    pure a = Cell (pure (empty, pure a))\n\n    Cell mF <*> Cell mX = Cell (liftA2 helper mF mX)\n      where\n        helper (inputF, foldF) (inputX, foldX) = (input, fold )\n          where\n            input = fmap Left inputF <|> fmap Right inputX\n\n            fold  = do\n                f <- Control.Foldl.handles _Left foldF\n                x <- Control.Foldl.handles _Right foldX\n                return (f x)\n\n-- | An updatable input value\ndata Updatable a = Updatable (Control -> Cell a)\n\ninstance Functor Updatable where\n    fmap f (Updatable m) = Updatable (fmap (fmap f) m)\n\ninstance Applicative Updatable where\n    pure a = Updatable (pure (pure a))\n\n    Updatable mf <*> Updatable mx = Updatable (liftA2 (<*>) mf mx)\n\n#if MIN_VERSION_base(4,11,0)\ninstance Semigroup a => Semigroup (Updatable a) where\n    (<>) = liftA2 (<>)\n\ninstance Monoid a => Monoid (Updatable a) where\n    mempty = pure mempty\n\n#else\ninstance Monoid a => Monoid (Updatable a) where\n    mempty = pure mempty\n\n    mappend = liftA2 mappend\n#endif\n\n\ninstance IsString a => IsString (Updatable a) where\n    fromString str = pure (fromString str)\n\ninstance Num a => Num (Updatable a) where\n    fromInteger = pure . fromInteger\n\n    negate = fmap negate\n    abs    = fmap abs\n    signum = fmap signum\n\n    (+) = liftA2 (+)\n    (*) = liftA2 (*)\n    (-) = liftA2 (-)\n\ninstance Fractional a => Fractional (Updatable a) where\n    fromRational = pure . fromRational\n\n    recip = fmap recip\n\n    (/) = liftA2 (/)\n\ninstance Floating a => Floating (Updatable a) where\n    pi = pure pi\n\n    exp   = fmap exp\n    sqrt  = fmap sqrt\n    log   = fmap log\n    sin   = fmap sin\n    tan   = fmap tan\n    cos   = fmap cos\n    asin  = fmap sin\n    atan  = fmap atan\n    acos  = fmap acos\n    sinh  = fmap sinh\n    tanh  = fmap tanh\n    cosh  = fmap cosh\n    asinh = fmap asinh\n    atanh = fmap atanh\n    acosh = fmap acosh\n\n    (**)    = liftA2 (**)\n    logBase = liftA2 logBase\n\n-- | Use a `Control` to obtain updatable input `Updatable`s\ndata Control = Control\n    { _checkBoxAt      :: Bool -> Text -> Cell Bool\n    , _spinButtonAt    :: Double -> Text -> Double -> Cell Double\n    , _hscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double\n    , _vscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double\n    , _entryAt         :: Text -> Text -> Cell Text\n    , _radioButton     :: forall a . Show a => Text -> a -> [a] -> Cell a\n    }\n\n-- | Build a `Text`-based user interface\ntextUI\n    :: Text\n    -- ^ Window title\n    -> Updatable Text\n    -- ^ Program logic\n    -> IO ()\ntextUI = ui textSetup processTextEvent\n  where\n    textSetup :: Gtk.HBox -> IO Gtk.TextBuffer\n    textSetup hBox = do\n        textView   <- Gtk.textViewNew\n        textBuffer <- Gtk.get textView Gtk.textViewBuffer\n        Gtk.set textView\n            [ Gtk.textViewEditable      := False\n            , Gtk.textViewCursorVisible := False\n            ]\n\n        hAdjust <- Gtk.textViewGetHadjustment textView\n        vAdjust <- Gtk.textViewGetVadjustment textView\n        scrolledWindow <- Gtk.scrolledWindowNew (Just hAdjust) (Just vAdjust)\n        Gtk.set scrolledWindow\n            [ Gtk.containerChild                 := textView\n            , Gtk.scrolledWindowShadowType       := Gtk.ShadowIn\n            , Gtk.scrolledWindowHscrollbarPolicy := Gtk.PolicyAutomatic\n            , Gtk.scrolledWindowVscrollbarPolicy := Gtk.PolicyAutomatic\n            ]\n        Gtk.boxPackStart hBox scrolledWindow Gtk.PackGrow 0\n        return textBuffer\n\n    processTextEvent :: Gtk.TextBuffer -> Text -> IO ()\n    processTextEvent textBuffer txt =\n        Gtk.set textBuffer [ Gtk.textBufferText := txt ]\n\n-- | Build a cell-based user interface\ncellUI\n    :: Text\n    -- ^ Window title\n    -> Updatable [(Text, Text)]\n    -- ^ Program logic\n    -> IO ()\ncellUI = ui cellSetup processCellEvent\n  where\n    cellSetup :: Gtk.HBox -> IO Gtk.VBox\n    cellSetup hBox = do\n        vbox <- Gtk.vBoxNew False 5\n        Gtk.boxPackStart hBox vbox Gtk.PackGrow 0\n        return vbox\n\n    processCellEvent :: Gtk.VBox -> [(Text, Text)] -> IO ()\n    processCellEvent vbox keyVals = do\n        cells <- Gtk.containerGetChildren vbox\n        mapM_ (Gtk.containerRemove vbox) cells\n\n        let createCell (key, val) = do\n                textView   <- Gtk.textViewNew\n                textBuffer <- Gtk.get textView Gtk.textViewBuffer\n                Gtk.set textView\n                    [ Gtk.textViewEditable      := False\n                    , Gtk.textViewCursorVisible := False\n                    ]\n                Gtk.set textBuffer [ Gtk.textBufferText := val ]\n                hAdjust <- Gtk.textViewGetHadjustment textView\n                vAdjust <- Gtk.textViewGetVadjustment textView\n                scrolledWindow <- do\n                    Gtk.scrolledWindowNew (Just hAdjust) (Just vAdjust)\n                Gtk.set scrolledWindow\n                    [ Gtk.containerChild :=\n                        textView\n                    , Gtk.scrolledWindowShadowType :=\n                        Gtk.ShadowIn\n                    , Gtk.scrolledWindowHscrollbarPolicy :=\n                        Gtk.PolicyAutomatic\n                    , Gtk.scrolledWindowVscrollbarPolicy :=\n                        Gtk.PolicyAutomatic\n                    ]\n                frame <- Gtk.frameNew\n                Gtk.set frame\n                    [ Gtk.containerChild := scrolledWindow\n                    , Gtk.frameLabel     := key\n                    ]\n                Gtk.boxPackStart vbox frame Gtk.PackNatural 0\n        mapM_ createCell keyVals\n        Gtk.widgetShowAll vbox\n\n-- | Build a `Diagram`-based user interface\ngraphicalUI\n    :: Text\n    -- ^ Window title\n    -> Updatable (Diagram Cairo)\n    -- ^ Program logic\n    -> IO ()\ngraphicalUI = ui setupGraphical processGraphicalEvent\n  where\n    setupGraphical :: Gtk.HBox -> IO Gtk.DrawingArea\n    setupGraphical hBox = do\n        drawingArea <- Gtk.drawingAreaNew\n        Gtk.boxPackStart hBox drawingArea Gtk.PackGrow 0\n        return drawingArea\n\n    processGraphicalEvent :: Gtk.DrawingArea -> Diagram Cairo -> IO ()\n    processGraphicalEvent drawingArea diagram = do\n        drawWindow <- Gtk.widgetGetDrawWindow drawingArea\n        (w, h) <- Gtk.widgetGetSize drawingArea\n        let w' = fromIntegral w / 2\n        let h' = fromIntegral h / 2\n        let diagram' = diagram # reflectY # translate (r2 (w', h'))\n        Diagrams.Backend.Gtk.renderToGtk drawWindow diagram'\n\n-- | Underlying function for building custom user interfaces\nui  :: (Gtk.HBox -> IO resource)\n    -- ^ Acquire initial resource\n    -> (resource -> event -> IO ())\n    -- ^ Callback function to process each event\n    -> Text\n    -- ^ Window title\n    -> Updatable event\n    -- ^ Event stream\n    -> IO ()\nui setup process title (Updatable k) = do\n    _ <- Gtk.initGUI\n\n    window <- Gtk.windowNew\n    Gtk.set window\n        [ Gtk.containerBorderWidth := 5\n        ]\n\n    vBox <- Gtk.vBoxNew False 5\n\n    hBox <- Gtk.hBoxNew False 5\n    Gtk.boxPackStart hBox vBox Gtk.PackNatural 0\n    a    <- setup hBox\n\n    Gtk.set window\n        [ Gtk.windowTitle         := title\n        , Gtk.containerChild      := hBox\n        , Gtk.windowDefaultWidth  := 600\n        , Gtk.windowDefaultHeight := 400\n        ]\n\n    let __spinButtonAt :: Double -> Text -> Double -> Cell Double\n        __spinButtonAt s0 label stepX = Cell (do\n            tmvar      <- STM.newEmptyTMVarIO\n            let minX = fromIntegral (minBound :: Int)\n            let maxX = fromIntegral (maxBound :: Int)\n            spinButton_ <- Gtk.spinButtonNewWithRange minX maxX stepX\n            Gtk.set spinButton_\n                [ Gtk.spinButtonValue    := s0\n                ]\n            _  <- Gtk.onValueSpinned spinButton_ (do\n                n <- Gtk.get spinButton_ Gtk.spinButtonValue\n                STM.atomically (STM.putTMVar tmvar n) )\n\n            frame <- Gtk.frameNew\n            Gtk.set frame\n                [ Gtk.containerChild := spinButton_\n                , Gtk.frameLabel     := label\n                ]\n\n            Gtk.boxPackStart vBox frame Gtk.PackNatural 0\n            Gtk.widgetShowAll vBox\n            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )\n\n    let __hscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double\n        __hscaleWithRange minY maxY s0 label stepY = Cell (do\n            tmvar      <- STM.newEmptyTMVarIO\n            slider <- Gtk.hScaleNewWithRange minY maxY stepY\n            Gtk.set slider\n                [ Gtk.rangeValue    := s0\n                ]\n            _  <- Gtk.onRangeValueChanged slider (do\n                n <- Gtk.get slider Gtk.rangeValue\n                STM.atomically (STM.putTMVar tmvar n) )\n            frame <- Gtk.frameNew\n            Gtk.set frame\n                [ Gtk.containerChild := slider\n                , Gtk.frameLabel     := label\n                ]\n            Gtk.boxPackStart vBox frame Gtk.PackNatural 0\n            Gtk.widgetShowAll vBox\n            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )\n\n    let __vscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double\n        __vscaleWithRange minY maxY s0 label stepY = Cell (do\n            tmvar      <- STM.newEmptyTMVarIO\n            slider <- Gtk.vScaleNewWithRange minY maxY stepY\n            Gtk.set slider\n                [ Gtk.rangeValue    := (-s0)\n                ]\n            _  <- Gtk.onRangeValueChanged slider (do\n                n <- Gtk.get slider Gtk.rangeValue\n                STM.atomically (STM.putTMVar tmvar (-n)) )\n            frame <- Gtk.frameNew\n            Gtk.set frame\n                [ Gtk.containerChild := slider\n                , Gtk.frameLabel     := label\n                ]\n            Gtk.boxPackStart hBox frame Gtk.PackNatural 0\n            Gtk.widgetShowAll hBox\n            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )\n\n    let __checkBoxAt :: Bool -> Text -> Cell Bool\n        __checkBoxAt s0 label = Cell (do\n            checkButton <- Gtk.checkButtonNewWithLabel label\n\n            Gtk.set checkButton [ Gtk.toggleButtonActive := s0 ]\n            tmvar <- STM.newEmptyTMVarIO\n            _     <- Gtk.on checkButton Gtk.toggled (do\n                pressed <- Gtk.get checkButton Gtk.toggleButtonActive\n                STM.atomically (STM.putTMVar tmvar pressed) )\n\n            Gtk.boxPackStart vBox checkButton Gtk.PackNatural 0\n            Gtk.widgetShowAll vBox\n            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )\n\n    let __entryAt :: Text -> Text -> Cell Text\n        __entryAt s0 label = Cell (do\n            entry_ <- Gtk.entryNew\n\n            frame <- Gtk.frameNew\n            Gtk.set frame\n                [ Gtk.containerChild := entry_\n                , Gtk.frameLabel     := label\n                ]\n            Gtk.set entry_ [ Gtk.entryText := s0 ]\n\n            tmvar <- STM.newEmptyTMVarIO\n            _     <- Gtk.on entry_ Gtk.editableChanged (do\n                txt <- Gtk.get entry_ Gtk.entryText\n                STM.atomically (STM.putTMVar tmvar txt) )\n\n            Gtk.boxPackStart vBox frame Gtk.PackNatural 0\n            Gtk.widgetShowAll frame\n            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )\n\n    let __radioButton :: Show a => Text -> a -> [a] -> Cell a\n        __radioButton label x xs = Cell (do\n            tmvar <- STM.newEmptyTMVarIO\n\n            vBoxRadio <- Gtk.vBoxNew False 5\n\n            let makeButton f y = do\n                    button <- f (show y)\n                    Gtk.boxPackStart vBoxRadio button Gtk.PackNatural 0\n                    _ <- Gtk.on button Gtk.toggled (do\n                        active <- Gtk.get button Gtk.toggleButtonActive\n                        if active\n                            then STM.atomically (STM.putTMVar tmvar y)\n                            else return () )\n                    return button\n\n            button <- makeButton Gtk.radioButtonNewWithLabel x\n            mapM_ (makeButton (Gtk.radioButtonNewWithLabelFromWidget button)) xs\n\n            frame <- Gtk.frameNew\n            Gtk.set frame\n                [ Gtk.containerChild := vBoxRadio\n                , Gtk.frameLabel     := label\n                ]\n            Gtk.boxPackStart vBox frame Gtk.PackNatural 0\n            Gtk.widgetShowAll frame\n            return (STM.takeTMVar tmvar, Control.Foldl.lastDef x) )\n\n    let control = Control\n            { _checkBoxAt      = __checkBoxAt\n            , _spinButtonAt    = __spinButtonAt\n            , _hscaleWithRange = __hscaleWithRange\n            , _vscaleWithRange = __vscaleWithRange\n            , _entryAt         = __entryAt\n            , _radioButton     = __radioButton\n            }\n\n    doneTMVar <- STM.newEmptyTMVarIO\n\n    let run (Cell m) = do\n            (stm, Fold step begin done) <- Gtk.postGUISync m\n            -- I don't know why this delay is necessary for diagrams output\n            Control.Concurrent.threadDelay 200000\n            let loop x = do\n                    let b = done x\n                    Gtk.postGUISync (process a b)\n                    let doneTransaction = do\n                            STM.takeTMVar doneTMVar\n                            return Nothing\n                    me <- STM.atomically (doneTransaction <|> fmap pure stm)\n                    case me of\n                        Nothing -> return ()\n                        Just e  -> loop (step x e)\n            loop begin\n\n    _ <- Gtk.on window Gtk.deleteEvent (liftIO (do\n        STM.atomically (STM.putTMVar doneTMVar ())\n        Gtk.mainQuit\n        return False ))\n    Gtk.widgetShowAll window\n    Control.Concurrent.Async.withAsync (run (k control)) (\\s -> do\n        Gtk.mainGUI\n        Control.Concurrent.Async.wait s )\n\n-- | A check box that returns `True` if selected and `False` if unselected\ncheckBox\n    :: Text\n    -- ^ Label\n    -> Updatable Bool\ncheckBox = checkBoxAt False\n\n-- | A `Double` spin button\nspinButton\n    :: Text\n    -- ^ Label\n    -> Double\n    -- ^ Step size\n    -> Updatable Double\nspinButton = spinButtonAt 0\n\n-- | A `Double` horizontal slider\nhscale\n    :: Text\n    -- ^ Label\n    -> Double\n    -- ^ Step size\n    -> Updatable Double\nhscale = hscaleAt 0\n\n-- | A `Double` vertical slider\nvscale\n    :: Text\n    -- ^ Label\n    -> Double\n    -- ^ Step size\n    -> Updatable Double\nvscale = vscaleAt 0\n\n-- | A `Text` entry\nentry\n    :: Text\n    -- ^ Label\n    -> Updatable Text\nentry = entryAt Data.Text.empty\n\n-- | A control that selects from one or more mutually exclusive choices\nradioButton\n    :: Show a\n    => Text\n    -- ^ Label\n    -> a\n    -- ^ 1st choice (Default selection)\n    -> [a]\n    -- ^ Remaining choices\n    -> Updatable a\nradioButton label a0 as =\n    Updatable (\\control -> _radioButton control label a0 as)\n\n-- | Same as `checkBox` except that you can specify the initial state\ncheckBoxAt\n    :: Bool\n    -- ^ Initial state \n    -> Text\n    -- ^ Label\n    -> Updatable Bool\ncheckBoxAt s0 label =\n    Updatable (\\control -> _checkBoxAt control s0 label)\n\n-- | Same as `spinButton` except that you can specify the initial state\nspinButtonAt\n    :: Double\n    -- ^ Initial state\n    -> Text\n    -- ^ Label\n    -> Double\n    -- ^ Step size\n    -> Updatable Double\nspinButtonAt s0 label x =\n    Updatable (\\control -> _spinButtonAt control s0 label x)\n\n-- | Same as `hscaleButton` except that you can specify the initial state\nhscaleAt\n    :: Double\n    -- ^ Initial state\n    -> Text\n    -- ^ Label\n    -> Double\n    -- ^ Step size\n    -> Updatable Double\nhscaleAt = hscaleWithRange (fromIntegral (minBound :: Int)) (fromIntegral (maxBound :: Int))\n\n-- | Same as `hscaleButton` except that you can specify the range and initial state\nhscaleWithRange\n    :: Double\n    -- ^ Minimum value\n    -> Double\n    -- ^ Maximum value\n    -> Double\n    -- ^ Initial state\n    -> Text\n    -- ^ Label\n    -> Double\n    -- ^ Step size\n    -> Updatable Double\nhscaleWithRange b0 b1 s0 label x =\n    Updatable (\\control -> _hscaleWithRange control b0 b1 s0 label x)\n\n-- | Same as `vscaleButton` except that you can specify the initial state\nvscaleAt\n    :: Double\n    -- ^ Initial state\n    -> Text\n    -- ^ Label\n    -> Double\n    -- ^ Step size\n    -> Updatable Double\nvscaleAt = vscaleWithRange (fromIntegral (minBound :: Int)) (fromIntegral (maxBound :: Int))\n\n-- | Same as `vscaleButton` except that you can specify the range and initial state\nvscaleWithRange\n    :: Double\n    -- ^ Minimum value\n    -> Double\n    -- ^ Maximum value\n    -> Double\n    -- ^ Initial state\n    -> Text\n    -- ^ Label\n    -> Double\n    -- ^ Step size\n    -> Updatable Double\nvscaleWithRange b0 b1 s0 label x =\n    Updatable (\\control -> _vscaleWithRange control b0 b1 s0 label x)\n\n-- | Same as `entry` except that you can specify the initial state\nentryAt\n    :: Text\n    -- ^ Initial state\n    -> Text\n    -- ^ Label\n    -> Updatable Text\nentryAt s0 label = Updatable (\\control -> _entryAt control s0 label)\n\n-- | Convert a `Show`able value to `Text`\ndisplay :: Show a => a -> Text\ndisplay = Data.Text.pack . show\n\n-- $examples\n--\n-- Mortgage calculator:\n--\n-- > {-# LANGUAGE ApplicativeDo     #-}\n-- > {-# LANGUAGE OverloadedStrings #-}\n-- > \n-- > import Typed.Spreadsheet\n-- > \n-- > main :: IO ()\n-- > main = textUI \"Mortgage payment\" $ do\n-- >   mortgageAmount     <- spinButton \"Mortgage Amount\"          1000\n-- >   numberOfYears      <- spinButton \"Number of years\"             1\n-- >   yearlyInterestRate <- spinButton \"Yearly interest rate (%)\"    0.01\n-- >   let n = truncate (numberOfYears * 12)\n-- >   let i = yearlyInterestRate / 12 / 100\n-- >   return (\"Monthly payment: $\" <> display (mortgageAmount * (i * (1 + i) ^ n) / ((1 + i) ^ n - 1)))\n--\n-- Example input and output:\n--\n-- <<http://i.imgur.com/nvRZ9HC.png Mortgage calculator program>>\n--\n-- Mad libs:\n--\n-- > {-# LANGUAGE OverloadedStrings #-}\n-- > \n-- > import Typed.Spreadsheet\n-- > \n-- > noun = entry \"Noun\"\n-- > \n-- > verb = entry \"Verb\"\n-- > \n-- > adjective = entry \"Adjective\"\n-- > \n-- > example =\n-- >     \"I want to \" <> verb <> \" every \" <> noun <> \" because they are so \" <> adjective\n-- > \n-- > main :: IO ()\n-- > main = textUI \"Mad libs\" example\n--\n-- The above program works because the `Updatable` type implements `IsString`\n-- and `Monoid`, so no `Applicative` operations are necessary\n--\n-- Example input and output:\n--\n-- <<http://i.imgur.com/k22An4Y.png Mad libs program>>\n--\n-- Sinusoid plot:\n--\n-- > {-# LANGUAGE OverloadedStrings #-}\n-- > \n-- > import Diagrams.Prelude\n-- > import Typed.Spreadsheet\n-- > \n-- > main :: IO ()\n-- > main = graphicalUI \"Example program\" $ do\n-- >     amplitude <- spinButtonAt 50  \"Amplitude (Pixels)\"   0.1\n-- >     frequency <- spinButtonAt 0.1 \"Frequency (Pixels⁻¹)\" 0.001\n-- >     phase     <- spinButtonAt 90  \"Phase (Degrees)\"      1\n-- > \n-- >     let axes = arrowBetween (p2 (0, 0)) (p2 ( 100,    0))\n-- >             <> arrowBetween (p2 (0, 0)) (p2 (-100,    0))\n-- >             <> arrowBetween (p2 (0, 0)) (p2 (   0,  100))\n-- >             <> arrowBetween (p2 (0, 0)) (p2 (   0, -100))\n-- > \n-- >     let f x = amplitude * cos (frequency * x + phase * pi / 180)\n-- > \n-- >     let points = map (\\x -> p2 (x, f x)) [-100, -99 .. 100]\n-- > \n-- >     return (strokeP (fromVertices points) <> axes)\n--\n-- Example input and output:\n--\n-- <<http://i.imgur.com/ueF0w7U.png Sinusoid plot>>\n--\n-- Factor diagram:\n--\n-- > {-# LANGUAGE OverloadedStrings #-}\n-- > \n-- > import Diagrams.Prelude\n-- > import Diagrams.TwoD.Factorization (factorDiagram')\n-- > import Typed.Spreadsheet\n-- > \n-- > main :: IO ()\n-- > main = graphicalUI \"Factor diagram\" $ do\n-- >     x <- spinButtonAt 3 \"Factor #1\" 1\n-- >     y <- spinButtonAt 3 \"Factor #2\" 1\n-- >     z <- spinButtonAt 3 \"Factor #3\" 1\n-- >     return (factorDiagram' [truncate x, truncate y, truncate z] # scale 10)\n--\n-- Example input and output:\n--\n-- <<http://i.imgur.com/eMvMtKk.png Factor diagram>>\n"
  },
  {
    "path": "stack.yaml",
    "content": "resolver: lts-8.2\n"
  },
  {
    "path": "typed-spreadsheet.cabal",
    "content": "Name: typed-spreadsheet\nVersion: 1.1.5\nCabal-Version: >=1.8.0.2\nBuild-Type: Simple\nLicense: BSD3\nLicense-File: LICENSE\nCopyright: 2015 Gabriella Gonzalez\nAuthor: Gabriella Gonzalez\nMaintainer: GenuineGabriella@gmail.com\nBug-Reports: https://github.com/Gabriella439/Haskell-Typed-Spreadsheet-Library/issues\nSynopsis: Typed and composable spreadsheets\nTested-With: GHC == 8.0.2, GHC == 8.2.2\nDescription:\n    This library provides a typed and composable API for building spreadsheets.\n    This differs from traditional spreadsheets in a few important ways:\n    .\n    * you specify the relationship between inputs and outputs at compile time,\n      not runtime, so that the relationship can be type-checked\n    .\n    * inputs of different types have different controls; for example, a `Bool`\n      input creates a checkbox and a `Double` input creates a spin button\n    .\n    * you can only output a single value; you simulate multiple outputs by\n      emitting a tuple of values\n    .\n    See the \"Typed.Spreadsheet\" module for full examples with code and pictures\nCategory: GUI\nSource-Repository head\n    Type: git\n    Location: https://github.com/Gabriella439/Haskell-Typed-Spreadsheet-Library\n\nLibrary\n    Hs-Source-Dirs: src\n    Build-Depends:\n        base           >= 4.9    && < 5   ,\n        async          >= 2.0    && < 2.3 ,\n        diagrams-cairo >= 1.3    && < 1.5 ,\n        diagrams-gtk   >= 1.3    && < 1.5 ,\n        diagrams-lib   >= 1.3    && < 1.5 ,\n        foldl          >= 1.1    && < 1.5 ,\n        gtk            >= 0.13   && < 0.16,\n        microlens                   < 0.5 ,\n        stm                         < 2.6 ,\n        text                        < 1.3 ,\n        transformers  >= 0.2.0.0 && < 0.6\n    if os(darwin)\n      frameworks: Cocoa\n    Exposed-Modules: Typed.Spreadsheet\n    GHC-Options: -O2 -Wall\n\nExecutable typed-spreadsheet-example-text\n    Hs-Source-Dirs: exec\n    Main-Is: Text.hs\n    Build-Depends:\n        base >= 4.9 && < 5  ,\n        text           < 1.3,\n        typed-spreadsheet\n    if os(darwin)\n      frameworks: Cocoa\n    GHC-Options: -O2 -Wall -threaded\n\nExecutable typed-spreadsheet-example-cell\n    Hs-Source-Dirs: exec\n    Main-Is: Cell.hs\n    Build-Depends:\n        base >= 4.9 && < 5  ,\n        text           < 1.3,\n        typed-spreadsheet\n    if os(darwin)\n      frameworks: Cocoa\n    GHC-Options: -Wall -threaded\n\nExecutable typed-spreadsheet-example-graphics\n    Hs-Source-Dirs: exec\n    Main-Is: Graphics.hs\n    Build-Depends:\n        base           >= 4   && < 5  ,\n        diagrams-lib   >= 1.3 && < 1.5,\n        typed-spreadsheet\n    if os(darwin)\n      frameworks: Cocoa\n    GHC-Options: -O2 -Wall -threaded\n"
  }
]