📜 ⬆️ ⬇️

Work with files in Dyalog APL

Hello. Today I will tell (and show) how the work with the files in Dyalog APL is organized. We will experiment with the “native” file system Dyalog - DCF, the rest of the files in this article are not considered. The topic of exception handling will also be covered. All experiments will be conducted on material from the past topic. Unfortunately, some images of bad quality, please excuse me, because I do not know a good hosting of images. So let's go.


What is DCF?


Dyalog APL has its own way of storing information - component files. The bottom line is:
a file is a sequence of “cells” (component), and in each of them you can write the value of only one variable. The following operations can be performed on a file: create, open, read a component, replace a component, attach a new component to the end, close and various special operations that are not considered in this article.
Let's try to open any file:

image
')
And we get an error, because there is no file. From this "experiment" we can draw 2 conclusions:
- to open the file, use the system function [] FTIE. Its arguments are the full file name on the left and the special file ID number (tie number), which is later used to access the file;
- error messages are displayed in the interpreter window indicating the cause of the error (in our case, this is FILE NAME ERROR). A little running ahead, I note that each error has its own number, which is used to intercept these very errors.
So, open the file failed. So you need to create it! The system function [] FCREATE with the same arguments as [] FTIE is used for this.

image

Well, now we have the test.dcf file with the identification number 1. By default (if you do not specify the full path) files appear on the desktop. The created files do not contain components, which can be verified using the system function [] FSIZE, passing the file number to the right.

image

We are only interested in the second element of the result of this function - it contains the number of the next free component. Since the number for the test.dcf file is 1, the number of components is zero.
To fill in the files, the system function [] FAPPEND is used, to which the variable or value on the left and the file number on the right must be passed. To verify that the information is actually recorded, use the [] FREAD function. It takes one argument of two values ​​— the file number and the component number.

image

To close a file, use the [] FUNTIE function with the file number. To make sure that there is no longer any connection with the file, we use the nyladic function [] FNUMS, which returns the vector of file numbers.

image

Using this knowledge, we will try to modify the program code from the previous example.

Some practice


Let's make some changes to the program:
1. We write in the file, the text used in the program and we will load it when it is executed.
2. We will write the texts of the functions into another file and we will execute them when the workspace is loaded, and when we exit - save back to the file.

Save and load text

First, we write a function that will initialize the text of the program - txtIni. We need to: open the file, if the file does not exist, create it and write the text, read the text in the global (for this function) variable and close the file.
The function header will look like this:

image

The function takes the full file name as an argument (fname). The variable tien will store the file number.
When working with files it is easy to make a mistake, so you need to use error handling tools. For our example, the following construct is suitable: Trap: Else: EndTrap, which is somewhat similar in ideology to try-catch.

image

Design: Trap 0 1000 defines error codes that should be intercepted. In this case, these are all system events (0) and all user events (1000). Also inside these bounds, you can define the processing of individual events using the constructions: Case and: CaseList. Note the use of the L1 tag: - it is used for unconditional jump after exception handling. The rest is simple: if the file contains components, read the first in the txt variable, if not, fill it with text and write to the file. Then close the file.
Next, you need to determine the sequence of actions in case of errors. For the absence of a file, we write a separate: Case, for the rest -: Else. The simplest thing to do in case of unexpected errors is to close all open files with the [] FUNTIE function with the argument [] FNUMS, and then issue a message in the interpreter window using the [] SIGNAL function. Its arguments are the text of the message on the right and the error code on the left. In our example, it will suffice to use the system variables [] DM (text) and [] EN (error code). If there is no file (or incorrectly specified name), this file is created and then the transition to the label is performed. Everything is very simple!

image8

In order for the loaded text to be used in the program, it is necessary to slightly change the functions of the application by adding references to the elements of the text nested vector txt.

image9

The argument was removed in the WhatNum function, since its value (the form header) is now taken from the file. All symbolic constants were replaced with reference to the elements of the vector txt with a call to the function “Disclose”, which converts the nested element of the vector into a symbolic vector. In the checkNum function, the changes are the same:

image10

Hide code

And now the most interesting thing: you can store variables in component files, but can you store functions? YES! To do this, you only need to convert the function to text and assign it to a variable, which will be what the saveFns function will do.
The conversion is done instantly: the system function [] CR (canonical representation) with the name of the function returns a character matrix with text as an argument. But the real magic begins with the use of the operator "Each".

image11

Thus, the variable all contains three texts of our functions, each text being a symbol matrix represented as a scalar (the rank is 0)!
The following is already described the procedure for writing to the file. At the end, add a call to the system function [] EX, which removes unnecessary objects from the workspace.

image12

Now it remains to write the initialization code, which will be executed when the workspace is loaded. The sequence of actions is: opening a file, reading, closing a file. Then APL magic begins to work again: with a slight movement of the hand, the vector all turns into full-fledged functions of the workspace! After loading the functions, you can call WhatNum and make sure that everything works.

image13

Fine. It remains only to save our functions to a file, change the contents of the [] LX system variable, and save the workspace. After that, only functions for working with files will be located in the workspace, and the application code will be loaded.

image14

To start the program, it is enough to open the workspace file, and if everything is done correctly, the application window will appear on the screen.

Total


Today you saw some APL magic, and at the same time you learned about such important things as working with files and handling exceptions. To be continued.

Source: https://habr.com/ru/post/124219/


All Articles