From 0b49a626f76ffda511d12923bfa9e2f732d04301 Mon Sep 17 00:00:00 2001 From: JordanMartinez Date: Mon, 13 Jul 2020 19:29:57 -0700 Subject: [PATCH] Add HeterogenousArrayLog (#173) * Add HeterogenousArrayLog * Regenerate readme * Add additional comments clarifying some things * Port comment explaining why Variant needs to be used to recipe Readme * Reword description to note exceptional nature of this approach * Add sum type version to compare with Variant version * Cleanup comment readability * purty formatting * Simplify examples Co-authored-by: Miles Frain --- README.md | 1 + recipes/HeterogenousArrayLog/.gitignore | 13 ++ recipes/HeterogenousArrayLog/README.md | 16 +++ recipes/HeterogenousArrayLog/nodeSupported.md | 2 + recipes/HeterogenousArrayLog/spago.dhall | 11 ++ recipes/HeterogenousArrayLog/src/Main.purs | 111 ++++++++++++++++++ recipes/HeterogenousArrayLog/web/index.html | 13 ++ recipes/HeterogenousArrayLog/web/index.js | 2 + 8 files changed, 169 insertions(+) create mode 100644 recipes/HeterogenousArrayLog/.gitignore create mode 100644 recipes/HeterogenousArrayLog/README.md create mode 100644 recipes/HeterogenousArrayLog/nodeSupported.md create mode 100644 recipes/HeterogenousArrayLog/spago.dhall create mode 100644 recipes/HeterogenousArrayLog/src/Main.purs create mode 100644 recipes/HeterogenousArrayLog/web/index.html create mode 100644 recipes/HeterogenousArrayLog/web/index.js diff --git a/README.md b/README.md index d747a4a8..2ea618c3 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ Running a web-compatible recipe: | | :heavy_check_mark: | [HelloHalogenHooks](recipes/HelloHalogenHooks) | A Halogen port of the ["HTML - Hello" Elm Example](https://elm-lang.org/examples/hello). | | | :heavy_check_mark: | [HelloReactHooks](recipes/HelloReactHooks) | A React port of the ["HTML - Hello" Elm Example](https://elm-lang.org/examples/hello). | | :heavy_check_mark: | :heavy_check_mark: | [HelloWorldLog](recipes/HelloWorldLog) | This recipe shows how to run a simple "Hello world!" program in either the node.js or web browser console. | +| :heavy_check_mark: | :heavy_check_mark: | [HeterogenousArrayLog](recipes/HeterogenousArrayLog) | This recipe demonstrates how to create a heterogenous array and process its elements. | | | :heavy_check_mark: | [ImagePreviewsHalogenHooks](recipes/ImagePreviewsHalogenHooks) | A Halogen port of the ["Files - Drag-and-Drop" Elm Example](https://elm-lang.org/examples/drag-and-drop). | | | :heavy_check_mark: | [NumbersHalogenHooks](recipes/NumbersHalogenHooks) | A Halogen port of the ["Random - Numbers" Elm Example](https://elm-lang.org/examples/numbers). | | | :heavy_check_mark: | [NumbersReactHooks](recipes/NumbersReactHooks) | A React port of the ["Random - Numbers" Elm Example](https://elm-lang.org/examples/numbers). | diff --git a/recipes/HeterogenousArrayLog/.gitignore b/recipes/HeterogenousArrayLog/.gitignore new file mode 100644 index 00000000..fcea5928 --- /dev/null +++ b/recipes/HeterogenousArrayLog/.gitignore @@ -0,0 +1,13 @@ +/bower_components/ +/node_modules/ +/.pulp-cache/ +/output/ +/generated-docs/ +/.psc-package/ +/.psc* +/.purs* +/.psa* +/.spago +/web-dist/ +/prod-dist/ +/prod/ diff --git a/recipes/HeterogenousArrayLog/README.md b/recipes/HeterogenousArrayLog/README.md new file mode 100644 index 00000000..4af2c477 --- /dev/null +++ b/recipes/HeterogenousArrayLog/README.md @@ -0,0 +1,16 @@ +# HeterogenousArrayLog + +This recipe demonstrates how to create a heterogenous array and process its elements. + +PureScript arrays are _homogeneous_, meaning that all values must have the same type. If you want to store values with different types in the same array (i.e. a _heterogeneous_ array), you should wrap all the types you wish to store in either a [sum type](https://github.com/purescript/documentation/blob/master/language/Types.md#tagged-unions) or a [Variant](https://pursuit.purescript.org/packages/purescript-variant). This recipe demonstrates both strategies. + +## Expected Behavior: + +Prints the following: +``` +---- Using Sum Type ---- +["a String value","4","true","false","82.4"] + +---- Using Variant Type ---- +["a String value","4","true","false","82.4"] +``` \ No newline at end of file diff --git a/recipes/HeterogenousArrayLog/nodeSupported.md b/recipes/HeterogenousArrayLog/nodeSupported.md new file mode 100644 index 00000000..7bd63dd1 --- /dev/null +++ b/recipes/HeterogenousArrayLog/nodeSupported.md @@ -0,0 +1,2 @@ +This file just indicates that the node backend is supported. +It is used for CI and autogeneration purposes. diff --git a/recipes/HeterogenousArrayLog/spago.dhall b/recipes/HeterogenousArrayLog/spago.dhall new file mode 100644 index 00000000..aa1634f9 --- /dev/null +++ b/recipes/HeterogenousArrayLog/spago.dhall @@ -0,0 +1,11 @@ +{ name = "HeterogenousArrayLog" +, dependencies = + [ "console", "effect", "psci-support", "variant", "arrays" ] +, packages = ../../packages.dhall +, sources = [ "recipes/HeterogenousArrayLog/src/**/*.purs" ] +} +{- +sources does not work with paths relative to this config + sources = [ "src/**/*.purs" ] +Paths must be relative to where this command is run +-} diff --git a/recipes/HeterogenousArrayLog/src/Main.purs b/recipes/HeterogenousArrayLog/src/Main.purs new file mode 100644 index 00000000..3644f128 --- /dev/null +++ b/recipes/HeterogenousArrayLog/src/Main.purs @@ -0,0 +1,111 @@ +module HeterogenousArrayLog.Main where + +import Prelude +import Data.Functor.Variant (SProxy(..)) +import Data.Variant (Variant) +import Data.Variant as Variant +import Effect (Effect) +import Effect.Class.Console (logShow) +import Effect.Console (log) + +main :: Effect Unit +main = do + log "---- Using Sum Type ----" + heterogenousArrayViaSumType + log "\n---- Using Variant Type ----" + heterogenousArrayViaVariant + +-------------- Sum Type Example -------------- +-- +-- Sum Type for array elements +data SumType + = Str String + | Integer Int + | Bool Boolean + | Num Number + +heterogenousArrayViaSumType :: Effect Unit +heterogenousArrayViaSumType = do + let + -- Create array + heterogenousArray :: Array SumType + heterogenousArray = + [ Str "a String value" + , Integer 4 + , Bool true + , Bool false + , Num 82.4 + ] + + -- Demonstrate how to process array elements with a function + -- that converts values of our SumType to strings for logging. + -- Note, you could create a Show instance for SumType instead. + showElement :: SumType -> String + showElement = case _ of + Str s -> s + Integer i -> show i + Bool b -> show b + Num n -> show n + -- + -- Show array + logShow $ map showElement heterogenousArray + +-------------- Variant Type Example -------------- +-- +-- Variant Type for array elements +-- Created from a "row type" of tags and other types +type VariantType + = Variant + ( typeLevelString :: String + , int :: Int + , boolean :: Boolean + , "this type level string must match the label of the row" :: Number + ) + +heterogenousArrayViaVariant :: Effect Unit +heterogenousArrayViaVariant = do + let + -- Setup some SProxy values with types matching those found within our VariantType + -- + -- Read: "This particular `SProxy` value has the type + -- `SProxy "typeLevelString"`..." + _typeLevelString :: SProxy "typeLevelString" + _typeLevelString = SProxy + + -- ... which differs from `SProxy "int"` and the other SProxy types below. + -- Note that we can write these on one line as: + _intValue = (SProxy :: SProxy "int") + + -- This shorthand style is also allowed: + _boolean = (SProxy :: _ "boolean") + + -- Any string may be used as a type-level label + _arbitraryTypeLevelString = (SProxy :: _ "this type level string must match the label of the row") + + -- Create array + heterogenousArray :: Array VariantType + heterogenousArray = + -- To create a value of type `Variant`, we must inject a value into + -- the data type using a type-level string that refers to the + -- corresponding row (i.e. a label-type association) + [ Variant.inj _typeLevelString "a String value" + , Variant.inj _intValue 4 + , Variant.inj _boolean true + -- You may also skip creating the SProxy helper values, and just write them inline: + , Variant.inj (SProxy :: _ "boolean") false + , Variant.inj _arbitraryTypeLevelString 82.4 + ] + + -- Demonstrate how to process array elements with a function + -- that converts values of our VariantType to strings for logging. + -- Note, you could create a Show instance for VariantType instead. + showElement :: VariantType -> String + showElement = + Variant.case_ + # Variant.on _typeLevelString identity + # Variant.on (SProxy :: _ "int") show -- inline example + # Variant.on _boolean show + # Variant.on _arbitraryTypeLevelString show + -- + -- Show array + logShow $ map showElement heterogenousArray diff --git a/recipes/HeterogenousArrayLog/web/index.html b/recipes/HeterogenousArrayLog/web/index.html new file mode 100644 index 00000000..254f8f68 --- /dev/null +++ b/recipes/HeterogenousArrayLog/web/index.html @@ -0,0 +1,13 @@ + + + + + + HeterogenousArrayLog + + + + + + + diff --git a/recipes/HeterogenousArrayLog/web/index.js b/recipes/HeterogenousArrayLog/web/index.js new file mode 100644 index 00000000..24ff58c0 --- /dev/null +++ b/recipes/HeterogenousArrayLog/web/index.js @@ -0,0 +1,2 @@ +"use strict"; +require("../../../output/HeterogenousArrayLog.Main/index.js").main();