Example of a dynamic webpage created using Dyalog APL

Here is a page I found which illustrates how web programming is done using Dyalog APL. Some people may think that APL is only good for writing the shortest code snippets possible or that it is only for solving puzzles, but, it seems to me that it can also be used for real world things; like creating actual web based psychological tests etc.

Link to the page is here :

MiServer: click orange see APL
Anyone who can write APL should be able to host it on the web.™
Home
:Class AdVocab : MiPage

    :Include #.HTMLInput                  ⍝ Useful functions for creating HTML pages
    :Field Public Action←''               ⍝ All action buttons have this name

    ⍝ All Buttons will have this name Action. Value will tell which one was pressed. 
    :Field Public FName←'First'           ⍝ Name of edit field
    :Field Public LName←'Last'            ⍝ Name of edit field
    :Field Public TName←'Teacher'         ⍝ Name of edit field
    :Field Public WorkF←'DadWork'         ⍝ Name of edit field
    :Field Public WorkM←'MomWork'         ⍝ Name of edit field    
    :Field Public DOBm←'1'                ⍝ Name of dropdown field
    :Field Public DOBd←'1'                ⍝ Name of dropdown field
    :Field Public DOBy←'2013'             ⍝ Name of dropdown field
    :Field Public Sex←'Male'              ⍝ Name of dropdown field
    :Field Public Test←''                 ⍝ Name of dropdown field Test: Dunn or Dolch or SH40
    :Field Public Word←''                 ⍝ Name of Edit field Vocabulary word
    :Field Public DebugOn←'1'             ⍝ turns logging 1=on 0=off
    :Field Public State←⎕NS ''            ⍝ holds all vars not avail from fields above

    Initialized←0                         ⍝ set to zero
    
    ⎕RL←1000⊥¯2↑⎕TS ⍝ random start from Steven Taylor ⍝ RandStart ⍬

    
    gvars←'INIT badword yes2bad WordTie CurMinMaxJmpLev cLev cLevs cnt yescnt Trys DATA ShLine ShScore' ⍝ global vars to save
    ∇ GetState
      ⍎gvars,'←State.(',gvars,')' ⍝ Extract saved state
    ∇

    ∇ PutState ⍝ Save State for next post
      ⍎'State.(',gvars,')←',gvars ⍝ "State" is public and will be saved in page
      Initialized←1
    ∇

    lbl←{⍺,(⊃,/' Cur=' ' Min=' ' Max=' ' Jmp=' ' Lev=',¨⍕¨⍵)} ⍝ utility fns used in testselect & nxtword

    ∇ DEBUG
      :Access Public
      ⍝ DEBUG SECTION. writes data every time a button is pushed.
      bob←{⊃,/(⍕¨⍵),¨' '} ⍝ turns nested num vec into min char vector
      logfile←'ts=',(bob ⎕TS),' LName=',LName,' Test=',Test,' Action=',Action,' Word=',Word
      :If Initialized
          logfile,←' CurMinMaxJmpLev=',(bob CurMinMaxJmpLev),' yescnt=',(⍕yescnt),' Trys=',(⍕Trys)
          logfile,←' cnt=',(⍕cnt),' cLev=',cLev
      :End
      logfile←⊂logfile
      'DEBUG.txt'writedata logfile
    ∇
    
    ∇ Render req;html;BR
      :Access Public
     
      :If Initialized ⋄ GetState
      :Else ⋄ yes2bad←0
          :If 0=⎕NC'ShLine'
              ShLine←'LARGE' 'Red' 'Big' 'Silent' 'Wet' '2' ⋄ ShScore←0
          :EndIf
      :EndIf
     
      :If DebugOn≡'1' ⋄ DEBUG ⋄ :EndIf ⍝ call DEBUG program ⍝ writes data for every button push.
     
      DoAction                        ⍝ If a button was pressed, deal with it
     
     
      BR←'<br>' ⍝ ⋄ NL←'<br>',CRLF
      req.Title'Adaptive Vocabulary Test'  ⍝ Page title
      html←('a href="/"'Enclose'Home')                                  ⍝ A link back to the index page
      html,←'h2'Enclose'Adaptive Vocabulary Test: 3 Short Tests: Dunn, Dolch, SH40'                            ⍝ Header in page
     
      html,←'Your help is very much appreciated. Please do the best you can. Your honest effort will'
      html,←' contribute to developing more accurate and concise tests.'
      html,←' Please enter your name, sex and birthdate once so 3 different test results may be linked together.'
      html,←BR,BR,'If you prefer to remain anonymous, please enter a unique fictious name, correct sex and a'
      html,←' birthdate that gives the correct year so that your data will still be useful to me. Thanks!'
      html,←BR,BR,'If AFTER doing the 3 tests and making your contribution to my science project you want to do it again or just'
      html,←' play you may, but please enter your first and last names as: "play" "play" so that this'
      html,←' data is not entered into my research database. Thank you, thank you, thank you!'
      html,←BR,BR,'Ok, FIRST enter ALL your information, and THEN click the "Dunn" test.'
      html,←' When you finish the "Dunn" test choose the "Dolch" test.'
      html,←' When you finish the "Dolch" test choose the "SH40" test. Thanks!'
     
      html,←BR,BR,'First Name=',('FName'Edit FName)
      html,←' Last Name=',('LName'Edit LName)
      html,←' Sex=',('Sex'DropDown('Male' 'Female')(,Sex))
      html,←BR,' Birth Month=',('DOBm'DropDown(⍕¨⍳12)(,DOBm))
      html,←' Birth Day=',('DOBd'DropDown(⍕¨⍳31)(,DOBd))
      html,←' Birth Year=',('DOBy'DropDown(⍕¨⌽1+(1↑⎕TS)-⍳100)(,DOBy))
      html,←' Teacher Name=',('TName'Edit TName)
      html,←BR,' Father''s Work=',('WorkF'Edit WorkF)
      html,←' Mother''s Work=',('WorkM'Edit WorkM)
      html,←BR,'NOW choose and complete the 3 tests in order -->',('Action'Submit'Dunn'),('Action'Submit'Dolch'),('Action'Submit'SH40')
     
      :If Test≡'SH40'
          html,←BR,BR,'Choose the one word that means the same thing, or most nearly the same thing as the first word'
          html,←BR,'(For example if I showed you--> LARGE: Red Big Silent Wet  [You should  choose Big])'
          html,←BR,'For this test only make your best guess. There is no penalty for guessing.'
          :If 1≠⍴,ShLine ⋄ html,←BR,BR,('Word'Edit 1⊃ShLine),(⊃,/'Action'∘Submit¨¯1↓1↓ShLine)
          :Else ⋄ html,←BR,BR,('Word'Edit(⊃ShLine)65) ⍝ show results
          :EndIf
     
      :ElseIf (Test≡'Dunn')∨(Test≡'Dolch')
          html,←BR,BR,'Do you know the meaning of this word?'
          html,←BR,BR,('Word'Edit Word 65)
          :If ~∨/'DONE'⍷Word ⍝ If not done show some more buttons.
              html,←BR,BR,'Action'Submit'Yes'   ⍝ A button named 'Action' with Caption 'Yes'
              html,←'Action'Submit'No'          ⍝ ... another button named 'Action' with Caption 'No'
          :End
      :End
     
      html←req('post'Form)html      ⍝ Put a 'submit' form around it
      req.Return html
    ∇

    ∇ DoAction
      :Select Action
      :Case 'Dunn' ⋄ testselect,⊂Test←Action
      :Case 'Dolch' ⋄ testselect,⊂Test←Action
      :Case 'SH40' ⋄ testselect,⊂Test←Action
      :CaseList 'Yes' 'No' ⋄ nxtword Action   ⍝ ⍝ check word, prep next word
      :CaseList ShLine ⋄ nxtword Action       ⍝ Do SH40
      :EndSelect
    ∇

    ∇ testselect msg;c;m;x;j;Lev;dtbl;tst;files;tday
      ⍝ select test parameters and find first word. from .DXV file
      ⎕FUNTIE ⎕FNUMS
      files←(⊂(⌽((⌽⎕WSID)⍳'\')↓⌽⎕WSID)),¨'\Intro\jbgames\AdVocab\DolchV' '\Intro\jbgames\AdVocab\DunnrV' '\Intro\jbgames\AdVocab\SH40'
      :If 'Dolch'≡tst←¯5↑1⊃msg  ⍝ Dolch test
          CurMinMaxJmpLev←2 1 14 1 1 ⋄ Trys←15
          cLevs←'DPP' 'DP','D',¨⍕¨⍳12 ⍝ data in DPP DP D1 to D12. DBAD is bad words
          WordTie←(1⊃files)⎕FTIE 0   ⍝  tie DolchV file.
          Word←(?⍴words)⊃words←⎕FREAD WordTie(1⊃CurMinMaxJmpLev) ⍝ new word
          cLev←(1⊃CurMinMaxJmpLev)⊃cLevs ⍝ level label for this word
      :ElseIf 'SH40'≡tst←¯4↑1⊃msg ⍝ Shipley 1st 40 test
          cLevs←,' '
          cLev←1⊃CurMinMaxJmpLev←1 1 40 0 1 ⋄ Trys←40 ⍝ if jmp=0 just give test in order
          WordTie←(3⊃files)⎕FTIE 0   ⍝  tie SH40 file.
          ShLine←cLev⊃⎕FREAD WordTie 1 ⍝ Shline looks like TALK Draw Eat Speak Sleep 3
          ShLine←{⎕ML←3 ⋄ (⍵≠' ')⊂⍵}ShLine
          ShScore←0
      :Else ⍝ DEFAULT ⍝ Dunn-Rankin
          CurMinMaxJmpLev←8 1 32 4 1 ⋄ Trys←15
          cLevs←'L',¨⍕¨⍳32 ⍝ data in L0 to L32. LBAD is bad words
          WordTie←(2⊃files)⎕FTIE 0   ⍝  tie DunnRV file.
          Word←(?⍴words)⊃words←⎕FREAD WordTie(1⊃CurMinMaxJmpLev) ⍝ new word
          cLev←(1⊃CurMinMaxJmpLev)⊃cLevs ⍝ level label for this word
      :End
      cnt←1 ⋄ yes2bad←yescnt←0 ⋄ badword←DATA←⍬ ⋄ INIT←CurMinMaxJmpLev,Trys,cnt,yescnt ⍝ set initial parameters
     
      PutState      ⍝ Store State
    ∇

    ∇ nxtword msg;c;m;x;j;Lev;dtbl;ans;name;sp;DolDun
      ⍝ get next word from FILE tied with WordTie in fns:testselect
      :If Initialized ⋄ GetState ⋄ :Else ⋄ testselect Test ⋄ :EndIf
      dtbl←{(-+/∧\⌽⍵∊' ')↓⍵} ⍝ delete trailing blanks
      sp←' ' ⋄ tday←⊃,/(4 ¯3 ¯3↑¨⍕¨3↑⎕TS)
      c m x j Lev←CurMinMaxJmpLev ⍝ ⋄ ⍎(⊃msg),'.State←0'
     
      :If (⊂msg)∊¯1↓1↓ShLine ⍝ its a Score shipley answer
          ShScore+←msg≡{(⍎(⍴⍵)⊃⍵)⊃1↓⍵}ShLine
          cnt←cnt+1
          :If Trys≥cnt
              ShLine←cnt⊃⎕FREAD WordTie 1 ⍝ Shline looks like TALK Draw Eat Speak Sleep 3
              ShLine←{⎕ML←3 ⋄ (⍵≠' ')⊂⍵}ShLine
              →Pau
          :ElseIf Trys<cnt
              ShLine←⊂'SH40 DONE Correct=',(⍕ShScore),' of 40 If all 3 tests done Thanks so much.' ⋄ yescnt←0
              DATA←⊂(⊂20↑'SH40'),(⊂2↑⍕CurMinMaxJmpLev[1]),('0 '),(2↑⍕cnt-1),(⊂4↑⍕ShScore),sp,(2↑⍕yes2bad),sp,tday,sp,DOBy,sp,(¯2↑DOBm),sp,(¯2↑DOBd),sp,(⊂1↑Sex),sp,(⊂20↑LName),sp,(⊂20↑FName),sp,(⊂20↑TName),sp,(⊂20↑WorkF),sp,(⊂20↑WorkM)
              writedata DATA ⍝ writes data to .txt file same name as workspace see above comment for order
              CurMinMaxJmpLev←¯3↓INIT ⋄ Trys cnt yescnt←¯3↑INIT ⋄ badword←DATA←⍬ ⍝ set initial parameters for program
              ⍝ testselect ,⊂Test
              →Pau
          :EndIf
      :EndIf
     
      ans←'Yes'≡msg
      :If yescnt=4
          :If 'e.'≡¯2↑Word ⋄ yescnt←0 ⍝ done w badword move on
              Word←(?⍴words)⊃words←⎕FREAD WordTie(1⊃CurMinMaxJmpLev) ⍝ new word
              cLev←(1↑CurMinMaxJmpLev)⊃cLevs  ⍝ problem line ********************************************************************
              →Pau
          :ElseIf ans ⋄ yes2bad+←1 ⋄ Word,←' CAREFUL NOT REAL WORD. Click Yes to Continue.'
              ⍝ following lines used if starting over if said yes to fake word
              Initialized←0 ⋄ cnt←1 ⋄ yes2bad←yescnt←0
              DolDun←(1+Action≡'Dunn')⊃(2 1 14 1 1)(8 1 32 4 1) ⍝ start parameters for Dolch and Dunn
              INIT←(CurMinMaxJmpLev←DolDun),Trys,cnt,yescnt
              →Pau
              ⍝ following code used if punishing saying yes to fake word
              ⍝ Lev←Lev⌊c ⋄ c←m⌈c-j←1⌈j-1 ⍝ bad so down level
              ⍝ CurMinMaxJmpLev←c m x j Lev
              ⍝ L.curr.Caption←('current :',(⍕cnt),' of ',⍕Trys)lbl CurMinMaxJmpLev
              →Pau
          :ElseIf ~ans ⋄ Word,←' GOOD NOT REAL WORD.  Click Yes to Continue.'
              →Pau
          :End
      :End
     
      :If ans ⋄ Lev←c ⋄ c←x⌊c+j←4⌊j+1                           ⍝ yes so up level
      :Else ⋄ Lev←Lev⌊m⌈c-1 ⋄ cLev←Lev⊃cLevs ⋄ c←m⌈c-j←1⌈j-1    ⍝ no so down level
      :End
     
      ⍝ DATA for each trial: word wordlevel ans(0/1) trial personslevel yes2bad today(y m d) dob(y m d) male(0/1) name
     
      ⍝ name←{⊂(⍵≠' ')/⍵}{¯1↓⊃,/⍵,¨','}{0=⍴,⍵:'XX' ⋄ ⍵}¨L.(lnam fnam).Text ⍝ lastname,firstmiddle use XX,XX if nothing entered
      ⍝ DATA,←⊂(⊂20↑Word),(⊂2↑⍕CurMinMaxJmpLev[1]),(2↑⍕ans),(2↑⍕cnt),(⊂4↑cLev),(3↑⎕TS),(3↑L.Date.IDNToDate 1↑L.Date.DateTime),L.grp.male.State,name
     
      DATA,←⊂(⊂20↑Word),(⊂2↑⍕CurMinMaxJmpLev[1]),(2↑⍕ans),(2↑⍕cnt),(⊂4↑cLev),sp,(2↑⍕yes2bad),sp,tday,sp,DOBy,sp,(¯2↑DOBm),sp,(¯2↑DOBd),sp,(⊂1↑Sex),sp,(⊂20↑LName),sp,(⊂20↑FName),sp,(⊂20↑TName),sp,(⊂20↑WorkF),sp,(⊂20↑WorkM)
      ⍝ L.data.Text←⍕↑⍕¨DATA
     Jump:⍝ L.prev.Caption←('previous:',(⍕cnt),' of ',⍕Trys)lbl CurMinMaxJmpLev
      cnt←cnt+1 ⋄ yescnt←ans×yescnt+1 ⋄ CurMinMaxJmpLev←c m x j Lev
      ⍝ L.curr.Caption←('current :',(⍕cnt),' of ',⍕Trys)lbl CurMinMaxJmpLev
     
      :If cnt≤Trys ⍝ This is main loop
          :If yescnt=4 ⍝ if said yes 4 times in a row check with a bad word
             ⍝ badword,←⊂L.word.Caption←(?⍴words)⊃words←⍎(1↑1⊃cLev),'BAD'  ⍝ new bad word from new level no dups
              badword,←⊂Word←(?⍴words)⊃words←(⎕FREAD WordTie(¯1+2⊃⎕FSIZE WordTie))~badword  ⍝ new bad word from last component no dups
          :Else
           ⍝ L.word.Caption←(?⍴words)⊃words←(⍎cLev←⍎'c⊃cLevs')~dtbl¨1⊃¨DATA ⍝ new word from new level no dups from WS
              Word←(?⍴words)⊃words←(⎕FREAD WordTie c)~dtbl¨1⊃¨DATA ⍝ new word from new level FILE.  no repeats from DATA
              cLev←c⊃cLevs ⍝ level label for this word
          :End
      :ElseIf 'DONE'≡4↑Word
          :If ans  ⍝ yes to Try Again reset screen for new testing
              CurMinMaxJmpLev←¯3↓INIT ⋄ Trys cnt yescnt←¯3↑INIT ⋄ badword←DATA←⍬ ⍝ set initial parameters for program
             ⍝ L.word.Caption←word←(?⍴words)⊃words←⍎cLev←⍎'(1↑CurMinMaxJmpLev)⊃cLevs' ⍝ new word from WS
              Word←(?⍴words)⊃words←⎕FREAD WordTie(1⊃CurMinMaxJmpLev) ⍝ new word from FILE
              cLev←(1⊃CurMinMaxJmpLev)⊃cLevs ⍝ level label for this word
              ⍝ L.(curr prev).Caption←('current   :1 of ',cap)('previous :0 of ',cap←(⍕Trys)lbl CurMinMaxJmpLev)
          :Else
              :If 'R'=1↑4⊃'.'⎕WG'APLVersion' ⋄ ⎕OFF ⋄ :Else ⋄ ⎕EX'L' ⋄ :End  ⍝ if runtime shutoff otherwise just end program
          :End
      :Else ⍝ finish up and write DATA to file and ask if want to try again
          Word←Test,' DONE Level=',cLev,' Choose Next Test' ⋄ yescnt←0
          writedata DATA ⍝ writes data to .txt file same name as workspace see above comment for order
      :End
     Pau:PutState  ⍝ Store State
    ∇
 
    ∇ {f}writedata x;tie;file;lf;nl
      ⍝ also used for Debugging MildServer on the server see Boot.Demo
      ⍝ file←⎕WSID,'.txt'
      :If 0=⎕NC'f' ⋄ f←'AdVocab.txt' ⋄ :End
      file←(⌽((⌽⎕WSID)⍳'\')↓⌽⎕WSID),'\Intro\jbgames\AdVocab\',f
      lf←⎕AV[3] ⋄ nl←⎕AV[4] ⍝ 2=linefeed 3=newline
      :Trap 0 ⋄ tie←file ⎕NCREATE 0
      :Else ⋄ tie←file ⎕NTIE 0 2
      :EndTrap
      (1↓¨⍕¨(x,¨nl),¨lf)⎕NAPPEND¨tie
      ⎕NUNTIE tie
    ∇
  
:EndClass

MiServer v2.1Introduction to MiServer

A guide to Dyalog’s “Mi Server” you can use for Web Programming.

1 Like

Both the site and the doc you link to is for the old MiServer 2. See its successor, MiServer 3, at https://miserver.dyalog.com/

1 Like