Skip to content

Commit

Permalink
Add HeterogenousArrayLog (#173)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
JordanMartinez and milesfrain authored Jul 14, 2020
1 parent 22ee469 commit 0b49a62
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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). |
Expand Down
13 changes: 13 additions & 0 deletions recipes/HeterogenousArrayLog/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/bower_components/
/node_modules/
/.pulp-cache/
/output/
/generated-docs/
/.psc-package/
/.psc*
/.purs*
/.psa*
/.spago
/web-dist/
/prod-dist/
/prod/
16 changes: 16 additions & 0 deletions recipes/HeterogenousArrayLog/README.md
Original file line number Diff line number Diff line change
@@ -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"]
```
2 changes: 2 additions & 0 deletions recipes/HeterogenousArrayLog/nodeSupported.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This file just indicates that the node backend is supported.
It is used for CI and autogeneration purposes.
11 changes: 11 additions & 0 deletions recipes/HeterogenousArrayLog/spago.dhall
Original file line number Diff line number Diff line change
@@ -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
-}
111 changes: 111 additions & 0 deletions recipes/HeterogenousArrayLog/src/Main.purs
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions recipes/HeterogenousArrayLog/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>HeterogenousArrayLog</title>
</head>

<body>
<script src="./index.js"></script>
</body>

</html>
2 changes: 2 additions & 0 deletions recipes/HeterogenousArrayLog/web/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
require("../../../output/HeterogenousArrayLog.Main/index.js").main();

0 comments on commit 0b49a62

Please sign in to comment.