Facade Functional Programming Suite

Post your working scripts, libraries and tools
robodesign
Posts: 714
Joined: 30 Sep 2017, 03:59
Facebook: marius.sucan
GitHub: mariussucan
Location: Romania
Contact:

Re: Facade Functional Programming Suite

23 Jan 2020, 08:27

I did not state you are the best of all AHK programmers ;-)... nor did I try to suggest it. And yes, there are a few highly advanced programmers here in AHK, but I bet they do not know only AHK.

My stance is that by knowing only AHK, it is hard to become a good developer, because it screws up the mindset, as you suggested. Luckily, I am not one of those relying on Goto/Gosub ^_^ . My worst offence is to rely on globals ^_^ .

And yes, I agree , anyone who can make a sensible contribution to the AHK community is definitely welcome. And... I emphasize again, your library is without doubt a good one... It only requires people to adjust a bit their mindset..

Anyways, good luck !

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
guest3456
Posts: 3150
Joined: 09 Oct 2013, 10:31

Re: Facade Functional Programming Suite

23 Jan 2020, 10:17

[Shambles] wrote:
22 Jan 2020, 20:15
Most of the time when you think you want a changing thing, what you really want is to build new code to do different things. Getting a handle on this is hard.
can you give an example of this? i guess we're really asking you to teach us when and how to do functional programming, which is why this is all so difficult

[Shambles]
Posts: 91
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

23 Jan 2020, 14:35

guest3456 wrote:
23 Jan 2020, 10:17
[Shambles] wrote:
22 Jan 2020, 20:15
Most of the time when you think you want a changing thing, what you really want is to build new code to do different things. Getting a handle on this is hard.
can you give an example of this? i guess we're really asking you to teach us when and how to do functional programming, which is why this is all so difficult
You should do functional programming when what you are doing is pure processing, not mutating 'the state of the world' (a phrase often used in functional programming but easy to understand if you are familiar with video games and can imagine storing the state of the video game world in a variable) and not performing I/O, and this should describe the vast majority of most realistic code. Most code is about processing. By chunking most of your side effects near execution entry and exit points (the main routine and event handlers) most of your code should not be 'broken up' by side effects and can therefore be easy to describe functionally (and thus be easy to test, debug, reuse, and (for a compiler) optimize).

That is slightly misleading. You really want to know several declarative programming paradigms (e.g. functional programming, logic programming, dataflow programming, etc.) and choose the one that fits your problem best. It won't always be functional programming.

Sadly, most programming paradigms are not taught any more, only imperative and OOP, which are the most dangerous and laborious. If you want to know what "declarative programming" means, a standard definition goes something like "the programmer describes what to do and the computer figures out how to do it", but what that means in practice (since all programming is 'describing how to do it') is the control flow and resource management is as implicit as possible (i.e. declarative programming uses few, if any, branches or loops and tends to use tracing garbage collection).

The reason most programming paradigms are no longer taught is because few programming languages can efficiently describe more than one and it is difficult to describe whole programs in any single declarative paradigm. The Lisp family of programming languages are the only ones that are especially well-suited to embedding multiple programming paradigms (because they have extremely simple, extremely regular syntax, which can be used to describe anything, and macros, which act as mini-compilers), allowing you to use whichever paradigm describes a portion of your program best and share data easily between the different paradigms. The Lisp family of programming languages fell out wide use during the AI winter.

But functional programming does not require much more infrastructure than imperative programming, so it is relatively easy to implement in conventional programming languages and mingle with code in conventional programming languages (like how Facade works).

As for the 'when you want a changing thing'...

When an imperative programmer wants to create some 'powerful' code they usually do it by mutating pointers or references to other code. In other words, they do it much like functional programming's higher-order functions, but instead of having the code accept the other code to call (in the form of said pointers or references) they have some data structure they change that stores the code to call. This is error-prone for the same reason changing any data structure is error-prone.

When a functional programmer wants to create some 'powerful' code they usually do it by constructing new code at run-time and calling it. Functions are just normal values after all. They can be passed as arguments and returned as values, and the combinators in the Func library do just that.

So when you want something to change its value under complex circumstances, instead of literally detecting the circumstances and mutating some variables, you could construct some code, at run-time if necessary (e.g. when the 'complex' part is the desired behavior can only be known based on user input), that accepts the 'circumstances' as arguments, and calculates the result. What was once a bunch of tests in branches that mutated some variables now becomes a reference to a function that computes a value.
guest3456
Posts: 3150
Joined: 09 Oct 2013, 10:31

Re: Facade Functional Programming Suite

23 Jan 2020, 21:48

[Shambles] wrote:
23 Jan 2020, 14:35
You should do functional programming when what you are doing is pure processing, not mutating 'the state of the world' (a phrase often used in functional programming but easy to understand if you are familiar with video games and can imagine storing the state of the video game world in a variable) and not performing I/O, and this should describe the vast majority of most realistic code. Most code is about processing. By chunking most of your side effects near execution entry and exit points (the main routine and event handlers) most of your code should not be 'broken up' by side effects and can therefore be easy to describe functionally (and thus be easy to test, debug, reuse, and (for a compiler) optimize).

That is slightly misleading. You really want to know several declarative programming paradigms (e.g. functional programming, logic programming, dataflow programming, etc.) and choose the one that fits your problem best. It won't always be functional programming.
i mean i guess ill use my example, my main script manipulates multiple game windows.. i'm doing image and pixel searches to determine the game state, and then moving windows around or changing z-order or hotkeys which send clicks to the game window, depending on the state that my image searches detect. half way through the life of the script, i decided to try to write unit tests, and found it nearly impossible, i had to create gui's to act as fake game windows etc.

my main script is just a big timer loop that keeps doing the image/pixel processing to determine what actions to take. i have a very difficult time trying to figure out how to do this the functional way, but i think its more my lack of knowledge that is the limiter

maybe something like this (pseudo):

Code: Select all

;before
WinGet, list, list
Loop, Parse, list, `,
   Process(A_LoopField)...
   
;after
WinGet, list, list
Loop, Parse, list, `,
   Array.Push(A_LoopField)      ; first convert from CSV to Array
Map(Func("Process"), Array))
not sure

[Shambles] wrote:
23 Jan 2020, 14:35
So when you want something to change its value under complex circumstances, instead of literally detecting the circumstances and mutating some variables, you could construct some code, at run-time if necessary (e.g. when the 'complex' part is the desired behavior can only be known based on user input), that accepts the 'circumstances' as arguments, and calculates the result. What was once a bunch of tests in branches that mutated some variables now becomes a reference to a function that computes a value.
this sounds important, but i'm not sure i understand it. can you come up with a quick example of the before and after?

[Shambles]
Posts: 91
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

24 Jan 2020, 10:22

This might seem like it is rambling. I am trying to lead you through the necessary insights to understand the answers you asked for, and I am trying to answer questions I believe you need to ask in addition to the ones you asked.
guest3456 wrote:
23 Jan 2020, 21:48
i mean i guess ill use my example, my main script manipulates multiple game windows.. i'm doing image and pixel searches to determine the game state, and then moving windows around or changing z-order or hotkeys which send clicks to the game window, depending on the state that my image searches detect. half way through the life of the script, i decided to try to write unit tests, and found it nearly impossible, i had to create gui's to act as fake game windows etc.

my main script is just a big timer loop that keeps doing the image/pixel processing to determine what actions to take. i have a very difficult time trying to figure out how to do this the functional way, but i think its more my lack of knowledge that is the limiter
Niklaus Wirth wrote a textbook with this title:
Algorithms + Data Structures = Programs

The title is insightful. The reason we should teach students algorithms and data structures is because those are what are used to describe programs, and the more of them a programmer knows, the easier it is for that programmer to describe programs and the more efficient their programs will be.

Textbooks that teach programming paradigms are rare, and courses that use them are rarer. Advanced Programming Language Design is the best one that I know of. The reason we should teach students programming paradigms is because using a suitable programming paradigm tends to make writing part of a program easier, because it makes parts of the algorithms implicit, so the original author does not have to write them and maintainers do not have to read or maintain them.

Using the right paradigm occasionally makes enough of a difference to seem to grant magical powers. For example, did you know that if you really understand OOP, you can write software that is impractical to hack or infect with malware? Capability-Based Computer Systems will teach you how.

One way to think of a programming paradigm is the operational (what it does in the machine) way I just described (implicit control flow and resource management, and sometimes error handling).

Another way to think of a programming paradigm is as a perspective.

One thing that makes programming difficult is humans' lack of foresight. We tend to not think ahead and have a very poor understanding of the implications of what we do and do not do. That is why we write programs that eventually corrupt their state.

Is there anywhere in human experience that these problems are minimized? Yes! Conventional mathematics (the kind taught in elementary school).

Conventional mathematics models things as permanent relationships. When solving an equation, the value of a variable never changes. You might solve it again for different values (or in programmer-speak "you might pass it different arguments") but within the same context (or in programmer-speak "call") it never changes (or in programmer-speak "the same variable might have different values in different calls but never in the same call"). Time stands still.

Functional programming is what happens when you use this perspective when programming. You stop thinking about change over time and start thinking about permanent relationships.

But change over time does occur and it matters! A computer that does not react to input is just an inefficient space heater!

Early functional programmers (e.g. those using Lisp in the 1960s) learned to separate the code that performs side effects from the code that performs processing. They used the functional programming paradigm where they could (for processing) and the imperative programming paradigm when they had to (for retaining the state of their program across events and performing I/O).

This was before "publish or perish" flooded academic journals with junk research, universities (and thus researchers) were defunded by governments because they were teaching students to think for themselves instead of being obedient drones (and then the universities became businesses that charge students as much as the market will bear for the training businesses should be providing on the job), and corporations invented an endless stream of products to sell (often creating the problems they get paid to solve). The end result of those malignant processes is a tech industry in decline resulting from a strange sort of amnesia from neophilia and dogmatic thought from marketing. If you are old enough and you are willing to pay attention to unpleasant truths, you will start noticing things like the current cloud computing craze sounds a lot like the bad old days of rent to never own time-sharing computing and functional reactive programming from the 1990s sounds a lot like some new researchers trying to take credit for dataflow programming from the 1960s.

Lets say you are in the throes of this malaise. Maybe you are someone that wants to sell a product that claims functional programming is a silver bullet. Maybe you are someone that actually believes functional programming is a silver bullet.

Is there some way to shoehorn side effects into the functional programming paradigm? Yes... Conventional mathematics can model time. Imagine a conventional graph where the X axis represents time moving from 0 at the beginning of a process onward and Y represents the function's value at that point in time. The function is still a fixed relationship between X and Y.

How does this translate to programming?

The changing real world can be thought of as that X axis that is the argument passed to your program that you think of as a function that produces output that can be thought of as the Y value at that point on the X axis. This is what is meant by "the state of the world".

Some modern programming languages, like Haskell, make you model things this way.

Haskell would make you use its complex type system and have documentation that claims programs written in Haskell are somehow pure (as in referentially transparent) despite clearly performing side effects by playing word games with what is meant by program and side effect. This trick involves claiming that programs written in Haskell merely compute the good and pure value representing the state of the world while the evil and dirty runtime system (which is somehow 'not Haskell') is what actually performs the side effects the state of the world describes. This argument is vacuous. It would define C as a purely functional programming language and allow one to argue it 'just has better syntax for describing the state of the world' (i.e. performing side effects). The reason programmers should care about side effects is that they happen (if you remove them, the program's meaning changes), when they happen (if you delay them, the program's meaning changes), and the order they happen in (if you reorder them, the program's meaning changes) matters, and any compiler's optimizer is going to have to treat Haskell code with side effects the same as imperative code with side effects.

The Haskell code would be arranged exactly like the code good functional programmers would have written in older programming languages.

What would an AutoHotkey-syntaxed outline of that look like?

A command-line program (like a compiler) would look like this:

Code: Select all

; Implement ReadWorld(A_Args) here.

; Implement ComputeWorld(World) here.

; Implement WriteWorld(World) here.

Main(A_Args)
{
    exit WriteWorld(ComputeWorld(ReadWorld(A_Args)))
}

Main(A_Args)
An event-driven program (like a video game) would look like this:

Code: Select all

; Initialize World here.

; Implement ReadWorld(World) here.

; Implement ComputeWorld(World) here.

; Implement WriteWorld(World) here.

TimerEventHandler()
{
    local
    global World
    World := ComputeWorld(ReadWorld(World))
    WriteWorld(World)
}

SetTimer, TimerEventHandler
In both kinds of programs ReadWorld performs input, ComputeWorld performs processing, and WriteWorld performs output. In the command-line program ReadWorld receives the command-line arguments and might perform additional input (e.g. read some files). In the event-driven program ReadWorld receives the old state of the world and probably performs additional input (e.g. reading the window's message queue for keyboard and mouse input). The command-line and event-driven programs differ in that the command-line program contains code that is executed once and the event-driven program contains code that is executed repeatedly.

These examples are unrealistic. They have been simplified to be easy to understand. Notably, event-driven programs usually consist of many event handlers, and each of those would have different code for input, processing, and output. Most hardware has different interrupts (and therefore different interrupt handlers) for updating the screen, updating the sound queue, reacting to key presses, reacting to mouse events, reacting to USB input (like gamepads), reacting to input on network interfaces, and so on. All of them would update the state of the world. Many of them would only add pending input to the state of the world, not perform any output, or only update an output queue, not perform any input.

Your program should look a lot like the event-driven program just described.

Why bother structuring it that way? You answered this question yourself when you found out how hard it was to test and debug code where I/O is mingled with processing.

Representing your program's state as a value also makes some interesting things, like time traveling debugging, possible.

I suggest writing programs this way:
1. Figure out what data your program requires to do what you want.
2. Figure out what you want to do to that data. This tells you what algorithms to use.
3. Knowing what algorithms to use tells you what data structures to use (e.g. searching a dictionary is efficient, searching an array is not).
4. Knowing what data structures to use tells you how to represent your 'world'.
5. Write the simplest possible output procedure(s) you can for your main procedure or event handlers. Test them. Debug them. Try to never change them again.
6. Write the simplest possible input procedure(s) you can for your main procedure or event handlers. Test them. Debug them. Try to never change them again.
7. Write the processing function(s) to update the world for your main procedure or event handlers.

Why this order?

Some of it, like the parts that tell you what algorithms and data structures you need, just have to be done that way.

Output procedures are easier to test and debug than input procedures. It is hard to know if you are receiving input if you cannot see or hear anything.

If you follow this plan, the code that is inherently difficult to test, the I/O code, is as simple as possible (and thus unlikely to be defective) and need not be regularly retested and redebugged.

It is easier to stay motivated when you can see progress being made, and the I/O code is what lets you literally see progress being made.

One problem remains. How do you test and debug a world changing function? It no longer performs any I/O, but it shoves all the complexity into one place, so it is likely to have defects.

Most good programming languages have a REPL. If your only experience programming is with AutoHotkey, this will be foreign to you. REPL stands for "read, evaluate, print, loop". They read code you type into them, evaluate it (i.e. execute it to get the resulting value), 'print' the result to the screen, then wait for more input. You might be wondering what it means to 'print a value to the screen'. Long ago, people programmed using something called a teleprinter that looked a lot like an old fashioned typewriter but was connected to the computer so that both the programmer and the computer could type. When either party finished typing something, the paper would scroll up. When you know that, the way the REPL works becomes more obvious. But what about values that aren't numbers or strings? Data structures are usually represented as the equivalent literal syntax. Things that have no equivalent literal syntax, like a function object or closure, are usually represented as something surrounded by 'angle brackets'.

A REPL session for an AutoHotkey-syntaxed programming language might look something like this:

Code: Select all

2 + 2
; 4
5 / 0
; Error: division by zero
Foo()
{
    X := []
    X.Push(1)
    X.Push(2)
    X.Push(3)
    return X
}
Foo()
; [1, 2, 3]
Func("Foo")
; <function>
In most programming languages you would break your world changing function down into a lot of separate functions that it would call, and you would test these at the REPL as you wrote each one. The world itself, along with any changes to it, would be observable because you could see the data structure at the REPL.

But AutoHotkey does not work like that. So what do you do?

Yeah... :roll: That is one of many reasons I do not enjoy programming in AutoHotkey despite it being useful and being good at it.

Another major reason is v1 does not actually report errors like in that fictional REPL session above. Luckily, someone wrote Facade.

What I do is write some throwaway visualization code for what I am working on.

But there really is no way to visualize a function value. So what do you do?

Yeah... :? That is an excellent reason to get all the function-constructing code written once, debugged, and never write such code again. Luckily, someone wrote Facade.

Hopefully this helps.
guest3456 wrote:
23 Jan 2020, 21:48
[Shambles] wrote:
23 Jan 2020, 14:35
So when you want something to change its value under complex circumstances, instead of literally detecting the circumstances and mutating some variables, you could construct some code, at run-time if necessary (e.g. when the 'complex' part is the desired behavior can only be known based on user input), that accepts the 'circumstances' as arguments, and calculates the result. What was once a bunch of tests in branches that mutated some variables now becomes a reference to a function that computes a value.
this sounds important, but i'm not sure i understand it. can you come up with a quick example of the before and after?
Your program is an example.

There are simple examples in Facade's documentation for Func_Applicable and Func_CIf.

Func_Default's code could be considered an example. Some parts of Facade are 'written in Facade', and it is one such part.
Last edited by [Shambles] on 26 Jan 2020, 09:50, edited 1 time in total.
guest3456
Posts: 3150
Joined: 09 Oct 2013, 10:31

Re: Facade Functional Programming Suite

24 Jan 2020, 14:25

[Shambles] wrote:
24 Jan 2020, 10:22
Hopefully this helps.
you are clearly very educated in computer science.. this reminds me of my first year at university when they were teaching us Scheme, and unsurprisingly, i hated it, couldn't get my head around it, i just wanted to build real world things, not all that theoretical stuff. its funny how this is coming full circle for me.

i may just have to start writing things from scratch following your framework, and see where it leads me
[Shambles] wrote:
24 Jan 2020, 10:22
These examples are unrealistic. They have been simplified to be easy to understand. Notably, event-driven programs usually consist of many event handlers, and each of those would have different code for input, processing, and output. Most hardware has different interrupts (and therefore different interrupt handlers) for updating the screen, updating the sound queue, reacting to key presses, reacting to mouse events, reacting to USB input (like gamepads), reacting to input on network interfaces, and so on. All of them would update the state of the world. Many of them would only add pending input to the state of the world, not perform any output, or only update an output queue, not perform any input.
yeah, see all of these interrupts which update the state of the world seem like the real world stuff that we are dealing with most of the time in AHK, which is why most of the people here are having such a hard time with your library. whereas it seems like functional programming is much more prevalent in something like Javascript

[Shambles] wrote:
24 Jan 2020, 10:22
Most good programming languages have a REPL. If your only experience programming is with AutoHotkey, this will be foreign to you. REPL stands for "read, evaluate, print, loop". They read code you type into them, evaluate it (i.e. execute it to get the resulting value), 'print' the result to the screen, then wait for more input. You might be wondering what it means to 'print a value to the screen'. Long ago, people programmed using something called a teleprinter that looked a lot like an old fashioned typewriter but was connected to the computer so that both the programmer and the computer could type. When either party finished typing something, the paper would scroll up. When you know that, the way the REPL works becomes more obvious. But what about values that aren't numbers or strings? Data structures are usually represented as the equivalent literal syntax. Things that have no equivalent literal syntax, like a function object or closure, are usually represented as something surrounded by 'angle brackets'.

A REPL session for an AutoHotkey-syntaxed programming language might look something like this
i tried to make a REPL for AHK by using AHK_H to run the code in a new thread.. here was a very basic implementation:
https://www.autohotkey.com/boards/viewtopic.php?p=124013#p124013
but by your definition above, it doesn't look like what i wrote was a REPL, but rather more like a dynamic executor

[Shambles]
Posts: 91
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

24 Jan 2020, 17:42

guest3456 wrote:
24 Jan 2020, 14:25
you are clearly very educated in computer science.. this reminds me of my first year at university when they were teaching us Scheme, and unsurprisingly, i hated it, couldn't get my head around it, i just wanted to build real world things, not all that theoretical stuff. its funny how this is coming full circle for me.

i may just have to start writing things from scratch following your framework, and see where it leads me
I am mostly self-taught. I read computer science journal articles (mostly from CiteSeer and professors' personal home pages) for fun.

Most people want to do things without thinking first. That is how we got into this situation where thousands people's ids and financial information are stolen every year because some greedy, shortsighted novice decided they did not need to learn anything before making a web storefront for some business, err, I mean some praiseworthy 'entrepreneur' made an innocent and completely unforeseeable mistake (like needlessly storing and then not encrypting customers' data AGAIN). There really is no substitute for knowing what you are doing, and learning how to make things well is not a waste of time.

If you are a programmer that is not interested in writing good code, you must be interested in writing bad code.

The point in doing things the right way is to reduce risk.
guest3456 wrote:
24 Jan 2020, 14:25
yeah, see all of these interrupts which update the state of the world seem like the real world stuff that we are dealing with most of the time in AHK, which is why most of the people here are having such a hard time with your library. whereas it seems like functional programming is much more prevalent in something like Javascript
AutoHotkey and JavaScript are more alike than they are different. As far as I can tell, most of AutoHotkey's design was lifted from Microsoft's ScriptIt (some of the bad syntax), JavaScript (similar but different type system insanity, almost identical Object, and the misunderstanding of Self's prototype-based OOP), and PHP (intentionally ignoring errors and continuing execution, and shallow wrapping of win32 and other APIs leading to inconsistent and overly complicated interfaces). Those programming languages would have been excellent choices in a programming language design course to show what not to do. Basing a programming language on only their bad parts is sadistic!

Brendan Eich intended to use Scheme for client-side programming of web browsers, but he only had 10 days to implement it and Netscape Communications' management forced him to use syntax similar to Java midways through. So of course he made a mess! He did not have time to do anything right and the catastrophic change mid-project is what lead to this and this. And we will all be paying the price for their lack of foresight for the foreseeable future (one does not simply replace JavaScript).

The difference between AutoHotkey and JavaScript is there are good parts to JavaScript. It is brain damaged (with a thoroughly hosed type system, no macros because of complex syntax, etc.) Scheme, but some parts of Scheme (like proper closures, some higher-order functions, and tracing garbage collection) still work in it.

Nope! JavaScript is not a language you should admire, nor is it one used for vastly more intellectual tasks.

For goodness sake, 'web apps' work by animating something that was intended to be a document format (it is right there in the HyperText Markup Language name)! This is like designing triangular wheels! It is astounding any of it works at all!

As for whether using Facade is practical or not, I have repeatedly stated that it performs general purpose processing, so it would be practical if you are performing any processing. I did not include any domain-specific features. It is basically just a safer (reports errors, better designed) version of AutoHotkey written in AutoHotkey.
guest3456 wrote:
24 Jan 2020, 14:25
i tried to make a REPL for AHK by using AHK_H to run the code in a new thread.. here was a very basic implementation:
https://www.autohotkey.com/boards/viewtopic.php?p=124013#p124013
but by your definition above, it doesn't look like what i wrote was a REPL, but rather more like a dynamic executor
Yes, the point in a REPL is to be able to load some code (e.g. by calling some "load" procedure or using an "include" statement) and data (by calling procedures to load data from files into variables) and manipulate both. It is not intended that you do most of your coding or processing in the REPL. Doing that is possible (by cutting and pasting working code into files and calling procedures to write data from variables into files), just uncomfortable. Whatever is in the REPL is lost when it is closed. It is intended for exploratory programming. You can use it to see if some code works the way you expect (e.g. Are you understanding the documentation correctly?) and to test if your ideas are bad (e.g. Is your code defective?).

AutoHotkey lacks both a REPL and the necessary infrastructure to support one. To support a REPL, you need the ability to dynamically load code into the same environment (read), an eval function to evaluate code in an environment (eval), and a standard interface built-in and user-defined types can use to define how to represent themselves as text (print). AutoHotkey lacks all of those.
[Shambles]
Posts: 91
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

03 Oct 2020, 04:01

I fixed a race condition. It could occur when a Stream (an immutable type) was shared by more than one 'thread'. It was caused by memoization.

I also added Dict_KeyValuePred(KeyPred, ValuePred) and Dict_KeyValueFunc(KeyFunc, ValueFunc).

Nothing has changed that should break code for some time.
[Shambles]
Posts: 91
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

06 Oct 2020, 18:14

I fixed defects in the hashing of floats (also in HashTable) and truncation in Op_Integer(X). They were caused by AutoHotkey's truncation being defective (e.g. 1.1e1 & -1 is 1 instead of 11).

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Steuerfachwissen and 23 guests