📜 ⬆️ ⬇️

Introduction to mobile xotcl

#! / bin / sh
# \
exec tclsh "$ 0" $ {1 + "$ @"}

package require XOTcl ; namespace import -force xotcl :: *

# Over the past two days, a couple of articles about programming PDAs in C # and C ++ have appeared on Habré. This prompted me to write a series of articles about the same thing, but at the same time to acquaint readers of Habr, and myself with such technologies, about which few people have heard, but which have almost no analogues. So, the result of the articles will be a program for PDAs that helps to learn something. It will work according to the method of cards: one side is the word unknown, the other its meaning. On the way somewhere we look through the cards, if the word unknown has already become known, then go to the next card, otherwise we look at its meaning and try to remember.
')
The language in which the application will be written is TCL. This magnificent language may not be unique. Thanks to his primitive syntax, the idea of ​​metaprogramming and DSL in it is implemented according to the maxim. For example, there is an extension TCL, written as a library to it, which turns it into a language similar to smalltalk and ruby: calling methods through sending messages, introspection of objects and classes, the ability to dynamically change classes and separate objects, the ability to change the class of an object (!) And , of course, meta-classes and method_missing. It is on this extension that I will write. His name is xotcl.


# Today I will create an application engine. Unlike the cards that we go through sequentially or randomly, I want those words that I don’t know were chosen more often, so you need to keep statistics. It is obvious that the question that will be asked is connected with this statistics, and also that the answer to the question - I know or do not know - the same is connected with this statistics. Let the question be an object of the Exam class with the appropriate methods pass, fail, question and answer. And the Exam class itself will be an instance of the Session metaclass that will deal with statistics. Thus, we have connected the logical relation of entities to the relation expressed in language.

# Below is the corresponding code.

Class Session -superclass Class ; # define Session metaclass

# Next I define an a-la method_missing method for processing code of the form: “Session data.db Exam”, where
# data.db - statistics file
# Exam is the name of the class, the file consists of lines of the form: “wins defeats { question answer } ”, where wins is the number of victories, defeats is the number of defeats, question is an unknown word, answer is its meaning
# The method loads statistics and saves it as an Exam class variable and defines the Exam class itself.

Session proc unknown { file_name class_name } {
Class $ class_name -parameter { id } ; # define class $ class_name

# I read the statistics from the file and save it in the array of knowledge as they say toads class variable
set id 0
set db [ open $ file_name r ]
while { ! [ eof $ db ] } {
foreach { wins defeats dictionary } [ gets $ db ] {
$ class_name set knowledge ($ id, wins) $ wins
$ class_name set knowledge ($ id, defeats) $ defeats
$ class_name set knowledge ($ id, dictionary) $ dictionary
incr id
}
}
close $ db
$ class_name set knowledge (count) $ id

# define class method to save statistics
$ class_name proc save { file_name } {
set db [ open $ file_name w ]
for { set id 0 } { $ id < [ [ self ] set knowledge (count) ] } { incr id } {
set wins [ [ self ] set knowledge ($ id, wins) ]
set defeats [ [ self ] set knowledge ($ id, defeats) ]
set dictionary [ [ self ] set knowledge ($ id, dictionary) ]
puts $ db [ list $ wins $ defeats $ dictionary ]
}
close $ db
}

# overload the create message handler
class instance
$ class_name proc create { args } {
# The code below determines which question to ask. Algorithm
# about the following: I make a segment of the segments is long
# which is equal to the ratio of the number of dips to the sum
# attempts. I normalize it, and then I take a random number from
# 0 to 1 and choose which segment it contains.
set current null
set i 0
set omega 0
for { set id 0 } { $ id < [ [ self ] set knowledge (count) ] } { incr id } {
set wins [ [ self ] set knowledge ($ id, wins) ] .0
set defeats [ [ self ] set knowledge ($ id, defeats) ] .0
set sum [ expr { $ wins + $ defeats } ]
set delta ($ id) [ expr { $ defeats / $ sum } ]
set omega [ expr { $ omega + $ delta ($ id) } ]
}
set probe [ expr { rand () * $ omega } ]
set sum 0
foreach key [ array names delta ] {
set current $ key
set sum [ expr { $ sum + $ delta ($ key) } ]
if { $ probe <$ sum } break
}
# pass control to the standard creation mechanism
# class instance with passing current parameter,
# which indicates the question to be asked.
next [ lindex $ args 0 ] -id $ current
}

# passed the test
$ class_name instproc pass { } {
[ [ self ] class ] incr knowledge ( [ my id ] , wins)
}

# failed test
$ class_name instproc fail { } {
[ [ self ] class ] incr knowledge ( [ my id ] , defeats)
}

# returns the question
$ class_name instproc question { } {
lindex [ [ [ self ] class ] set knowledge ( [ my id ] , dictionary) ] 0
}

# returns the answer
$ class_name instproc answer { } {
lindex [ [ [ self ] class ] set knowledge ( [ my id ] , dictionary) ] 1
}

return $ class_name
}

# Below is a simple example of using the written part of the program.

# Create an Exam object (actually a class) of a class (actually
# meta-class) Session and load statistics into it from
# data.db file
Session data.db Exam

Exam test ; # Create test
puts [ test question ] ; # Find out what question
# If the question is green, then we pretend that we don’t know it and
# look at the answer otherwise proudly say I know
if { [ string equal [ test question ] green ] } {
puts [ test answer ]
test fail
} {
test pass
}
test destroy ; # delete object

Exam save 2data.db ; # save statistics

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


All Articles