⬆️ ⬇️

Practice IronScheme



I am sure that you will stop playing “meat”, because what I am about to tell you will seem very interesting to you, if only because you will not understand many special terms.

Jaroslav Hasek




Part 1 Introduction to Scheme

Part 2 Groove in the Scheme

Part 3 Practicing IronScheme



Practice



Now we will create several applications that are closer to real life than the examples from the previous article. Philosophical issues and the basics of development, we discussed in previous articles, so this will consist mainly of code. I hope that the code will be easy to read, so I will not provide it with abundant comments.

')

First, let's look at how you can access .net classes from IronScheme



The program on IronScheme begins with the import of libraries:

(import (rnrs) (ironscheme) ) 


To use functions for interacting with the CLR, you need to import the library (ironscheme clr):

 (import (rnrs) (ironscheme) (ironscheme clr) ) 


Now we have the following functions:

(clr-namespaces)

Returns all imported namespaces.



(clr-reference reference)

Connects an assembly to an application, for example (clr-reference System.Web).



(clr-using namespace)

Imports a namespace: (clr-using System.IO).



(clr-call type method instance arg ...)

Calls the object method.



(clr-cast type expr)

Brings the object to the specified type.



(clr-is type expr)

Checks if the object is of the specified type.



(clr-new type arg ...)

Creates an instance of the class and passes the arguments to the constructor.



(clr-new-array type size)

Creates an array with the specified type and size.



(clr-event-add! type event instance handler)

Adds an event handler.



(clr-event-remove! type event instance handler)

Removes an event handler.



(clr-field-get type field instance)

Get field value.



(clr-field-set! type field instance expr)

Assign a field value.



(clr-prop-get type property instance)

Returns the value of the property.



(clr-prop-set! type property instance expr)

Sets the value of the property.



(clr-static-call type method arg ...)

Call a static method.



(clr-static-event-add! type event handler)

Adds a handler for a static event.



(clr-static-event-remove! type event handler)

Removes a handler.



(clr-static-field-get type field)

Returns the value of a static field.



(clr-static-field-set! type field expr)

Sets the value to a static field.



(clr-static-prop-get type property)

Returns the value of a static property.



(clr-static-prop-set! type property expr)

Sets the value of a static property.



Hello, world 2.0



Let's try? Create a hello-world-clr.ss file with the contents:

 (import (rnrs) (ironscheme) (ironscheme clr) ) (clr-static-call Console WriteLine "Hello, world") 


This example demonstrates calling the static WriteLine method of the System.Console class.



Just a timer



Now the example is more interesting, we start the timer.



As usual, we first import the libraries:

 (import (rnrs) (ironscheme) (ironscheme clr) ) 


Import the namespace:

 (clr-using System.Threading) 


For ease of use, we will write two clr call wrapper functions. The first function creates an object of class Timer, the second changes the basic parameters of the timer:

 (define (timer-new handler) (clr-new Timer handler) ) (define (timer-change timer due-time period) (clr-call Timer Change timer (clr-cast System.Int32 due-time) (clr-cast System.Int32 period)) ) 




Casting with clr calls is needed to bring views from the internal IronScheme to .Net types.



Another useful function would be to block the main thread of the application so that the program does not end:

 (define (console-block) (clr-static-call Console WriteLine "Press <Enter> to terminate") (clr-static-call Console ReadLine) ) 


To use a timer, you must first declare a handler function:

 (define (time-handler obj) ;; some code ) 


Then create a timer object:

 (define timer (timer-new time-handler)) 


And we start the timer specifying the period and delay:

 (timer-change timer delay period) 


Now all together, an example prints the number of operations to the console.

Full source example of using the timer
 (import (rnrs) (ironscheme) (ironscheme clr) ) (clr-using System.Threading) ;; *************************************** (define (timer-new handler) (clr-new Timer handler) ) (define (timer-change timer due-time period) (clr-call Timer Change timer (clr-cast System.Int32 due-time) (clr-cast System.Int32 period)) ) (define (console-block) (clr-static-call Console WriteLine "Press <Enter> to terminate") (clr-static-call Console ReadLine) ) ;; *************************************** (define counter 0) (define period 1000) ;;ms (define (time-handler obj) (set! counter (+ counter 1)) (displayln counter) ) (define timer (timer-new time-handler)) (timer-change timer 0 period) (console-block) 






We work with Oracle DB



I give an example of connecting and querying Orcale DBMS. I believe that the reader can already figure it out himself, so I will not describe what is happening here and how. Initially, the program declared functions for working with Oracle, then for the already familiar Timer. Then a connection to the database is created and a request is made by timer, the result of the request is output to the console.

The example is taken from a real application used for monitoring. Naturally confidential code fragments are replaced by “*****”, but they are not critical for understanding or using the example to develop your own programs.



Source code for an example of working with an Oracle database
 (import (rnrs) (ironscheme) (ironscheme clr) ) ;; **************** Oracle **************;; (clr-reference System.Data) (clr-reference System.Data.OracleClient) (clr-using System.Data.OracleClient) (define (ora-connection-new connection-string) (clr-new OracleConnection (clr-cast System.String connection-string)) ) (define (ora-connection-open connection) (clr-call OracleConnection Open (clr-cast OracleConnection connection)) ) (define (ora-connection-create connection-string) (define connection (ora-connection-new connection-string)) (ora-connection-open connection) connection ;; return ) (define (ora-command-new connection sql-string) (clr-new OracleCommand (clr-cast System.String sql-string) (clr-cast OracleConnection connection)) ) (define (ora-command-parameter-add command key value) (clr-call OracleParameterCollection Add (clr-prop-get OracleCommand Parameters command) (clr-cast System.String key) (clr-cast System.Object value) ) ) (define (ora-execute-reader command) (clr-call OracleCommand ExecuteReader (clr-cast OracleCommand command)) ) (define (ora-read reader) (clr-call OracleDataReader Read (clr-cast OracleDataReader reader)) ) (define (ora-get-value reader key) (clr-call OracleDataReader GetValue reader (clr-call OracleDataReader GetOrdinal reader key) ) ) (define (ora-get-string reader key) (clr-call Object ToString (ora-get-datetime reader key)) ) (define (ora-get-int32 reader key) (clr-call OracleDataReader GetInt32 reader (clr-call OracleDataReader GetOrdinal reader key) ) ) (define (ora-get-datetime reader key) (clr-call OracleDataReader GetDateTime reader (clr-call OracleDataReader GetOrdinal reader key) ) ) ;;***************************************;; ;; **************** Timer ***************;; (clr-using System.Threading) (define (timer-new handler) (clr-new Timer handler) ) (define (timer-change timer due-time period) (clr-call Timer Change timer (clr-cast System.Int32 due-time) (clr-cast System.Int32 period)) ) (define (console-block) (clr-static-call System.Console WriteLine "Press <Enter> to terminate") (clr-static-call System.Console ReadLine) ) ;;***************************************;; ;;######## GLOBAL #########;; (define connection-string "Data Source=*****;User ID=*****;Password=*****;") ;;#########################;; (define (complect-print reader) (import (srfi :13)) (let loop ((index 1)) (if (ora-read reader) (begin (display " (") (display (string-pad-right (number->string index) 5)) (display (string-pad-right (ora-get-value reader "*****") 15)) (display " ") (display (string-pad-right (ora-get-value reader "*****") 20)) (display " ") (display (ora-get-int32 reader "*****")) (display " ") (display (string-pad-right (ora-get-value reader "*****") 25)) (display " ") (display (ora-get-string reader "*****")) (displayln ")") (loop (+ index 1)) ) ) ) ) (define (complect-display connection status) (define sqlStr "select * from ***** where ***** = :complect_status") (define cmd (ora-command-new connection sqlStr)) (define reader '()) (ora-command-parameter-add cmd "complect_status" status) (set! reader (ora-execute-reader cmd)) (display "(complect-status ") (displayln status) (complect-print reader) (displayln ")") (clr-call OracleDataReader Close reader) ) (define (time-handler obj) (define connection (ora-connection-create connection-string)) (clr-static-call System.Console Clear) (displayln "\n;; ************************************************************************* ;;\n") (complect-display connection 1) (newline) (complect-display connection 2) (newline) (complect-display connection 3) (newline) (complect-display connection 4) (displayln "\n;; ************************************************************************* ;;\n") (clr-call OracleConnection Close connection) ) (define timer (timer-new time-handler)) (timer-change timer 0 3000) (console-block) 






WindowsForms



And in conclusion I will give a simple example of a window application. In this example, I did not bother with .NET call wrappers, since I was important demonstration of the principle, the fact that it is possible. Of course, if you wrap up calls, the size of the code will be reduced, due to reuse.

 (import (rnrs) (ironscheme) (ironscheme clr) ) (clr-reference System.Windows.Forms) (clr-using System.Windows.Forms) (define main-form (clr-new Form)) (clr-prop-set! Form Text main-form "--== Hello, world ==--") (clr-prop-set! Form Size main-form (clr-new System.Drawing.Size 640 480)) (define lbl-message (clr-new Label)) (clr-prop-set! Label Text lbl-message "Message: \"Hello, Windows Forms(IronScheme) World!\"") (clr-prop-set! Label Size lbl-message (clr-new System.Drawing.Size 320 20)) (clr-prop-set! Label Location lbl-message (clr-new System.Drawing.Point 150 200)) (clr-call Form+ControlCollection Add (clr-prop-get Form Controls main-form) lbl-message) (clr-static-call Application Run (clr-cast Form main-form)) 




As a conclusion



In this article I tried to demonstrate that for Scheme nothing is impossible, at least executable over .NET. This does not mean that you should drop the familiar C # and start coding on Scheme. Of course, Scheme programming has certain advantages, it becomes clear as consciousness penetrates deeper into Lisp ideology. But still, support from the C # studio with ReSharper everyone there, is left far behind Scheme as the main language for developing for .NET. Of course, you can implement first-class support for Lisp over .NET, but obviously not many would need it otherwise they would have done it a long time ago. However, Lisp and in particular Scheme can be extremely useful as an embedded language. In such a role, it has certain advantages over other embedded languages. With Lisp, you can implement readable and flexible configuration files, a console interface for managing an application, transferring data over a network, and more. But more on this later in the following articles.

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



All Articles