Thursday 1 January 2015

Functional Programming (PureScript)

PureScript Simple DOM (created by Ashley Towns .. and other Open Source contributors)


Important Note: The following was prepared before having read any PureScript books (and only after just having managed to get PureScript Compiler installed thanks to help from Hardy Jones). See below PureScript By Example Git Repo containing working solutions based my application of code samples and custom commentary from the textbook.
  • Link to GitHub Repo here (of the PureScript Simple DOM)
  • Setup
    • Install PureScript  with the commands cabal install cabal-install and cabal install purescript (recommend avoiding having to run 'cabal update', as it breaks GHCi for Haskell), which downloads, builds, configures, and installs:
      • monad-unify-0.2.2
      • pattern-arrows-0.0.2
      • ansi-wl-pprint-0.6.7.1
      • optparse-applicative-0.11.0.1
      • purescript-0.6.2
    • Refer to the following Issue for help I got and Lessons Learnt showing how to install PureScript https://github.com/aktowns/purescript-simple-dom/issues/18
    • Check your current PATH by typing the following in terminal $PATH
    • When you run which cabal it should return the location of the Cabal Executable (i.e. /Users/<your_user_name>/Library/Haskell/bin/cabal)
    • Check where your Cabal Executables are installed by going to the ~/.cabal  cd ~/.cabal directory and inspecting the contents of a where-is-my-stuff.txt File by opening it (i.e. subl where-is-my-stuff.txt).
    • Edit your ~/.bash_profile File (i.e. subl ~/.bash_profile) and add the following line to it to add the directory containing Cabal Executables to the PATH (which will include subdirectories of ~/Library/Haskell/bin as well): export PATH="$HOME/Library/Haskell/bin:$PATH" 
    • Download the latest PureScript Releases and extract it (i.e macos.tar.gz) into the PATH directories) such as ~/Library/Haskell/bin. This will create a subdirectory called /purescript (i.e. ~/Library/Haskell/bin/purescript), which contains the PureScript Compiler executables (allowing you to run commands like psc --help)
    • Finally, reload your current shell by source-ing the ~/.bash_profile with source ~/.bash_profile, which will ensure that when you run cabal --version it returns confirming that the cabal-install version that is installed matches the same version that it built, configured, and installed when you first ran cabal install cabal-install
    • Install and update NPM and Grunt project dependencies npm install -g grunt grunt-init grunt-cli bower and npm update -g grunt grunt-init grunt-cli bower
    • Note that this Grunt project has already been pre-configured with a package.json file and a Gruntfile.js
    • Install Bower dependencies bower install
    • Build with Grunt grunt (uses the Zombie Gem to perform headless Browser testing of the DOM using Node.js)
    • View Grunt commands grunt --help
    • View PureScript Compiler commands  psc --help
    • Try the PureScript Compiler REPL Interface  psci
  • About the Toolkit
    • PureScript Simple DOM is a cross-platform GUI Toolkit (lower level library) wrapper that aims to translate underlying JavaScript API methods into PureScript equivalents to enable imperative-style UI programming using the functional programming paradigm. 
    • PureScript Simple DOM provides an API that may be understood by referring to the Module Documentation (API.md).
    • Since PureScript is a purely functional language (does not support object-orientation or mutable variables without use of IO Actions), the translation is not as simple as translating from JavaScript to another imperative language (using wrappers for marshalling data types and mapping functions and objects), instead the PureScript Simple DOM toolkit wrappers must translate underlying JavaScript API methods into the special Eff Actions that must be caged in the Eff Monad (defined in the PureScript Prelude Module), similar to in Haskell where IO Actions (IO Functions that create IORef wrappers, which represent a pointer to a pure value, enabling event-driven UI callbacks to read and write to the global application state) may be caged in the IO Monad. The Eff Monad handles native effects whilst generating efficient JavaScript.
  • Understanding the GitHub Repo

/bower_components/*  { Bower dependencies installed after running bower install }

/node_modules/*  { Node.js NPM dependencies installed after running npm install }

/outputs/*  { this directory is created as a result of running grunt }

/js/*  { requires Node.js dependencies and called by a Grunt command to run the PureScript tests against the HTML file }

/src/*  { contains individual Safe PureScript Modules (and Unsafe ones too in a subdirectory) that match the API Module Documentation }

/tests/* { contains HTML template and PureScript file that uses QuickCheck to verify that PureScript Simple DOM interacts (read, write) with the Browser Window, HTML Document and Elements.

.bowerrc { generates the defined directory 'bower_components' and installs all bower dependencies in sub-directories after running  bower install }

API.md
  • The Module Documentation structure is as follows:
    • AJAX
      • Algebraic Data Types (ADTs) Type Annotation definitions using the data keyword and the :: symbol (compiler infers correct type) (i.e. data <type_constructor> :: <data_constructors> )
      • Function definitions (using currying) in the Type Signatures (i.e. <argument_1> -> <argument_2> -> <argument_3> )
      • Existential Types using the forall keyword to inform the compiler not to care about the type of data from a Type Class, eliminating the need for the type variable 
    • HTML Document
    • HTML Element
    • URI Encoding, Decoding, Parameterization, and JSON Conversion
    • UI Event Handling
    • Web Browser Navigator Info
    • DOM Arrows { Syntactic Sugar that defines Combinators that store DOM Arrow instances of Eff, Maybe, and Just HTML Element ordinary Functions that are applied to Functors (which contain only Values) and extended into Applicative Functors. Note: Arrows define computations that may be Chained. Monads are a computational strategy that define a container for chainable Eff Functions (Actions) and are a subset of Arrows }
    • Web Browser DOM Component Types
    • Unsafe AJAX
    • Unsafe HTML Document
    • Unsafe HTML Element
    • Unsafe UI Event Handling
    • Unsafe Web Browser Navigator Info
    • Unsafe DOM Arrows 
    • Unsafe Utilities
    • Unsafe Web Browser Window Attributes
}

bower.json { bower.json is a manifest of metadata for Bower that includes Package definitions and dependencies for development and production environments. The following command bower install is run from a terminal to install:

  • purescript-foldable-traversable#0.1.6 bower_components/purescript-foldable-traversable
    • ├── purescript-arrays#0.3.0
    • ├── purescript-control#0.2.1
    • ├── purescript-either#0.1.4
    • ├── purescript-maybe#0.2.1
    • ├── purescript-monoid#0.1.5
    • └── purescript-tuples#0.2.3
  • purescript-strings#0.4.2 bower_components/purescript-strings
    • └── purescript-maybe#0.2.1
  • purescript-math#0.1.0 bower_components/purescript-math
  • purescript-quickcheck#0.3.2 bower_components/purescript-quickcheck
    • ├── purescript-arrays#0.3.0
    • ├── purescript-either#0.1.4
    • ├── purescript-exceptions#0.2.2
    • ├── purescript-foldable-traversable#0.1.6
    • ├── purescript-math#0.1.0
    • ├── purescript-maybe#0.2.1
    • ├── purescript-random#0.1.1
    • ├── purescript-strings#0.4.2
    • └── purescript-tuples#0.2.3
  • purescript-sets#0.1.1 bower_components/purescript-sets
    • ├── purescript-arrays#0.3.0
    • ├── purescript-foldable-traversable#0.1.6
    • ├── purescript-maps#0.1.5
    • ├── purescript-maybe#0.2.1
    • └── purescript-tuples#0.2.3
  • purescript-tuples#0.2.3 bower_components/purescript-tuples
    • ├── purescript-arrays#0.3.0
    • ├── purescript-control#0.2.1
    • └── purescript-monoid#0.1.5
  • purescript-maybe#0.2.1 bower_components/purescript-maybe
    • └── purescript-control#0.2.1
  • purescript-arrays#0.3.0 bower_components/purescript-arrays
    • ├── purescript-control#0.2.1
    • └── purescript-maybe#0.2.1
  • purescript-random#0.1.1 bower_components/purescript-random
  • purescript-exceptions#0.2.2 bower_components/purescript-exceptions
  • purescript-control#0.2.1 bower_components/purescript-control
  • purescript-either#0.1.4 bower_components/purescript-either
    • └── purescript-control#0.2.1
  • purescript-monoid#0.1.5 bower_components/purescript-monoid
    • ├── purescript-arrays#0.3.0
    • └── purescript-maybe#0.2.1
  • purescript-maps#0.1.5 bower_components/purescript-maps
    • ├── purescript-arrays#0.3.0
    • ├── purescript-foldable-traversable#0.1.6
    • ├── purescript-math#0.1.0
    • ├── purescript-maybe#0.2.1
    • ├── purescript-strings#0.4.2
    • └── purescript-tuples#0.2.3
 }

Gruntfile.js PureScript Simple DOM is a Grunt project that uses Gruntfile.js to configure tasks. When run with the command grunt, it checks that Grunt is installed locally using the Node.js require() system, and if it is found then the Grunt CLI loads the local installation of the Grunt library, and applies and executes the tasks that have been configured in the Gruntfile.js. 
The Grunt "wrapper" function module.exports = function(grunt) { currently passes configuration data to the grunt.initConfig method

Custom project-specific tasks are defined in external .js files and loaded using the grunt.loadNpmTasks method, including: 

  • grunt-contrib-copy
  • grunt-contrib-clean
  • grunt-execute
  • grunt-purescript


The Gruntfile is currently configured so that when:
  • grunt or grunt default is run, it Registers the Tasks:
    • clean
    • make
    • test
  • grunt test is run, it Registers the Tasks:
    • pscMake:tests
    • copy
    • execute:tests  
  • grunt make is run, it Registers the Tasks:
    • pscMake:lib
    • docgen
    • dotPsci (creates a .psci file)
When I first ran grunt errors were encountered, prompting me to raise this Issue on GitHub (initially because I couldn't get PureScript in my PATH, but now this is resolved and psc commands are recognised). To get all the tests to pass, just comment out the final 'userAgent' test on Line 122 (i.e. replace Line 122 with   -- userAgent navigator >>= (\name -> quickCheck' 1 $ name == "Mozilla/5.0 Chrome/10.0.613.0 Safari/534.15 Zombie.js/2.0.0-alpha31")). Currently I'm trying to figure out why replacing the userAgent value with the userAgent value that is found when using Chrome Dev Tools, running ```self```, and expanding the Window object (i.e. Window > clientInformation > userAgent) 





.psci { configuration file for the interactive mode of the PureScript PSC Compiler, which is generated when grunt make command is run  }

package.json { package.json is a manifest of metadata for this Grunt project that installs the Modules and associated Dependencies from the /node_modules/ directory when the Node.js Package Manager command npm install is run from a terminal. The output installs:
  • ws@0.6.4  node_modules/zombie/node_modules/ws
  • contextify@0.1.11 node_modules/zombie/node_modules/jsdom/node_modules/contextify
  • grunt-contrib-copy@0.5.0 node_modules/grunt-contrib-copy (Copy files and folders)
  • grunt-purescript@0.5.3 node_modules/grunt-purescript
  • grunt-execute@0.1.5 node_modules/grunt-execute
  • grunt-contrib-clean@0.5.0 node_modules/grunt-contrib-clean (Cleans files and folders)
    • └── rimraf@2.2.8
  • grunt@0.4.5 node_modules/grunt
    • ├── which@1.0.8
    • ├── dateformat@1.0.2-1.2.3
    • ├── eventemitter2@0.4.14
    • ├── getobject@0.1.0
    • ├── colors@0.6.2
    • ├── rimraf@2.2.8
    • ├── async@0.1.22
    • ├── hooker@0.2.3
    • ├── grunt-legacy-util@0.2.0
    • ├── exit@0.1.2
    • ├── nopt@1.0.10 (abbrev@1.0.5)
    • ├── lodash@0.9.2
    • ├── coffee-script@1.3.3
    • ├── glob@3.1.21 (inherits@1.0.0, graceful-fs@1.2.3)
    • ├── minimatch@0.2.14 (sigmund@1.0.0, lru-cache@2.5.0)
    • ├── underscore.string@2.2.1
    • ├── iconv-lite@0.2.11
    • ├── findup-sync@0.1.3 (glob@3.2.11, lodash@2.4.1)
    • ├── grunt-legacy-log@0.1.1 (underscore.string@2.3.3, lodash@2.4.1)
    • └── js-yaml@2.0.5 (esprima@1.0.4, argparse@0.1.16)
  • zombie@2.5.1 node_modules/zombie
    • ├── ms@0.7.0
    • ├── lazybird@1.0.0
    • ├── mime@1.2.11
    • ├── debug@2.1.1 (ms@0.6.2)
    • ├── iconv-lite@0.4.5
    • ├── tough-cookie@0.12.1 (punycode@1.3.2)
    • ├── eventsource@0.1.4 (original@0.0.5)
    • ├── bluebird@2.5.3
    • ├── request@2.51.0 (caseless@0.8.0, aws-sign2@0.5.0, json-stringify-safe@5.0.0, forever-agent@0.5.2, tunnel-agent@0.4.0, stringstream@0.0.4, oauth-sign@0.5.0, qs@2.3.3, node-uuid@1.4.2, mime-types@1.0.2, combined-stream@0.0.7, form-data@0.2.0, http-signature@0.10.0, bl@0.9.3, hawk@1.1.1)
    • ├── ws@0.6.4 (options@0.0.6, ultron@1.0.1, nan@1.4.1)
    • └── jsdom@1.4.0 (browser-request@0.3.3, xmlhttprequest@1.6.0, cssom@0.3.0, nwmatcher@1.3.3, parse5@1.3.0, htmlparser2@3.8.2, cssstyle@0.2.22, contextify@0.1.11)
}



PureScript By Example (created by Luke Schoen)



Sublime Text 2 Plugin for PureScript (created by Hardy Jones)

Link to GitHub Repo here

Setup
  • Copy the Git Repo into a new sub-directory in the Sublime Text 2 Packages directory 
    • cd ~/Library/Application\ Support/Sublime\ Text\ 2/Packages
    • git clone https://github.com/joneshf/sublime-purescript
  • Restart Sublime Text 2
PureScript Syntax Highlighting & Code Snippets
  • After Setup, go to Sublime Text 2 menu 
    • View > Syntax > PureScript
  • Enter a Code Snippet keyword (until "instance      instance" appears in the Drop-Down) and then select "instance      instance" (using Up/Down Keys) and then Press Tab and PureScript "instance" code block template will auto-populate (i.e. for example, the 'instance' keyword may be used, as it is contained between the <tabTrigger></tagTrigger> tags of the /Snippets/instance.sublime-snippet file) )

    Reference Documentation (Sublime Text 2 Plugins) 


    Events
    •  ATTENDING Ruby Conference (RubyConf) (Melbourne, 4 - 7th Feb 2015)
      • 7pm, Wed 4 Feb, Opening Party, Trunk Bar & Restaurant, 275 Exhibition St, Melbourne
      • 4:30pm, Sat 7th Feb, Family Picnic, Flagstaff Gardens, Corner of Williams St & La Trobe St, Melbourne
      • 8pm, Sat 7th Feb, After Party, City of Melbourne Bowling Club, Within Flagstaff Gardens near Dudley St, Melbourne

    Books
    • 20% Progress Developing Web Applications with Haskell and Yesod
    • 20% Progress Graphical User Interfaces in Haskell (by Gideon Sireling)
    • Pending UML for Java Programmers
    • TODO PureScript by Example (LeanPub)

    Links

    IN PROGRESS (NOT WORKING) Deploying Haskell on Heroku

    No comments:

    Post a Comment