&'
&' Py'N'APL Demo
&' --------------------------
&' 

&' ⍝ Start a Python interpreter
py←⎕NEW Py.Py

&'
&' ⍝ Evaluate a Python expression
py.Eval '2+2'

&'
&' ⍝ Python expressions may take arguments:
'⎕+⎕' py.Eval 2 2

&'
&' ⍝ There is automatic translation between datatypes
&' ⍝ Python has                   APL has
&' ⍝ int/float/long/complex  ←→   Numbers
&' ⍝ Lists, tuples           ←→   Vectors
&' ⍝ Strings                 ←→   Character vectors
&' ⍝ Dictionaries            ←→   Namespaces 
py.Eval '[1,2,3,4,[5,6,7],"Quack"]'
'repr(⎕)' py.Eval ⊂1 2 3 4 (5 6 7) 'Quack'

&'
&' ⍝ Python does not support higher-order arrays by itself
&' ⍝ By default, those are turned into lists of lists
'repr(⎕)' py.Eval ⊂5 5⍴⍳25

&'
&' ⍝ numpy: Python library that adds higher-order arrays
&' ⍝ If it is installed, Py'N'APL supports its arrays
py.Import'numpy'
'2*numpy.array(⎕)' py.Eval ⊂5 5⍴⍳25

&'
&' ⍝ Python has a datatype called a dictionary (name-value mapping)
&' ⍝ These map onto namespaces.
ns←⎕NS⍬
ns.(foo bar baz qux)←⍳4
'repr(⎕)' py.Eval ns

&'
&' ⍝ These translations work both ways
ns←py.Eval '{"foo": 10, "bar": 20, "baz": 30, "qux": 40}'
ns.⎕NL¯2
ns.(foo bar baz qux)

&'
&' ⍝ It's also possible for Python code to call back into APL
callback←{⎕←'hi ',⍵⋄⍵×2}
'APL.fn("#.callback")(2*⎕)' py.Eval 4

&'
&' 
&' ⍝ Python objects can be accessed from APL by "reference"
&' ⍝ An APL object is created with the same fields and functions as the 
&' ⍝ Python object, and accessing them calls Python.
&' 
py.Exec¨ 'class X: y=10' 'x=X()'
py.Eval'x.y'
x←py.Eval'x'
x.y
x.y←20
py.Eval'x.y'

&'
&' 
&' ⍝ This can be used to access Python modules
nltk←py.Import'nltk'
&' ⍝ 'nltk' is now a reference to the nltk Python module, which does natural
&' ⍝ language processing
nltk

&' ⍝ Retrieve its docstring (Python documentation)
{↑⍵⊆⍨~⍵∊⎕TC}nltk.__doc__

&'
&' ⍝ Instantiate a Python class
ltr←nltk.stem.WordNetLemmatizer⍬
ltr

&'
&' ⍝ Call a function on it
&' ⍝ Note: all functions are shy and ambivalent
&' ⍝   - right argument: vector of positional arguments
&' ⍝   - left argument: keyword arguments
&'
&' ⍝   foo.bar(ab, cd, ef=gh, ij=kl)     ←→
&' ⍝   (('ef' gh) ('ij' kl)) foo.bar (ab cd)
+ltr.lemmatize∘⊂¨'ducks' 'oxen' 'cacti' 'corpora'

&' 
&' ⍝ Now that we have natural language processing, retrieve some text
twitter←py.Import 'twitter'
api←demo.TwitCred twitter.Api⍬

&' ⍝ List of tweet objects
ts←(⊂'screen_name' 'dyalogapl') api.GetUserTimeline ⍬
⍴ts
⎕PW↑⍤1↑ts.text

&'
&' ⍝ Of course, multiple Python modules can be used alongside each other 

&' 
&' ⍝ Get all the words in the 10th tweet...
+nltk.word_tokenize ⊂ts[10].text

&'
&' ⍝ Find which part of speech they are...
+nltk.pos_tag ⊂nltk.word_tokenize ⊂ts[10].text

&' 
&' ⍝ Extract all the nouns...
⊃¨w/⍨(⊂'NN')≡¨2↑¨2⊃¨w←nltk.pos_tag ⊂nltk.word_tokenize ⊂ts[10].text

&' ⍝ Without having to write a line of Python. 
&' ⍝ It is also possible the other way around. 
&'
&'

