Facade Functional Programming Suite

Post your working scripts, libraries and tools for AHK v1.1 and older
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Facade Functional Programming Suite

24 Nov 2018, 11:15

Facade is intended to replace most of AutoHotkey's processing constructs, to provide error reporting and reduce sources of defects.

It is more heavily inspired by combinatory logic (see the Func library of combinators) than lambda calculus. This works well in AutoHotkey v1, which does not support closures. It would still be useful in AutoHotkey v2.


Special Thanks
  • GeekDude provided constructive criticism that led to documentation including an Intention chapter for orientation to the libraries and using ordered dictionaries.
  • xcc provided constructive criticism that led to providing Func_DllFunc(NameOrPtr, Types*) and ConcatZipWith functions (instead of ConcatMap functions).
Last edited by [Shambles] on 11 Nov 2019, 09:42, edited 5 times in total.
geek
Posts: 1052
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: Facade Functional Programming Suite

24 Nov 2018, 13:08

First off, good work! I love to see people attempting to improve the AutoHotkey experience.
AutoHotkey is verbose.

Code written atop Facade is less verbose.
Could you provide an example of verbosity in AutoHotkey that this library mitigates?
AutoHotkey conflates Objects with dictionaries.

All user-defined types have methods that only make sense for dictionaries.
I don't know that conflates is the right word here, as it often implies confusion or a lack of intention. AutoHotkey defines very few object types instead trying to rely on great flexibility of existing types. There was no confusion, the choice was very explicit and I would go as far as to say well implemented.

AutoHotkey has always been a very weakly typed language, so to start introducing a ton of object types would be rather out of place. On the other hand maybe it would be very useful, it wasn't set up that way so I can't say for sure. Lexikos designed the object system to be as unobtrusive as possible while supporting users to implement whatever wacky functionality they might want on top of it. If you want to create an object that discards or modifies the default method behaviors you (for the most part) can. If you decide that you want to use an object as a list then later modify it like a dictionary, you can. If you decide that you want to prevent your list from being treated as a dictionary, by all means create a class that does that. I'll stick with the more flexible default objects.
AutoHotkey conflates Objects' interfaces with their contents.

Storing a string key containing the name of a method clobbers that method.
I agree, this is a bit of a problem especially when it comes to reading in user (or API) provided data. If the provided data defines a value for something like base or _NewEnum you can end up with a really broken object. That said, you can define a class with overridden __Get and __Set behaviors that mitigate this bad behavior. You don't have to create separate Get and Set functions. Although, I'm talking about OOP solutions not functional, so for the purposes of this library I guess it doesn't matter.

When you're using the objects for creating OOP classes I hold that this is a good thing. Being able to treat the key/value system the same regardless of whether your value is a number/string/object/function reference is a very flexible behavior. AHK would be worse off if users were able to create key/value pairs that existed separately from the key/function pairs with the default object. A separate data type, or in your case a function library, can be useful in that case.

In case anyone was wondering how you would go about creating your own class that can be used for safe dictionary behaviors, this could be one way you would go about it in an OOP style while preserving some basic functionality like for loops.
Spoiler
AutoHotkey Objects have unreliable indexing.

String keys are case-folded and floating point number keys are associated by their current string representation instead of their value.

HashTables have reliable indexing.
How is the indexing in AHK's objects unreliable? The behavior is predictable and repeatable following a well defined set of rules. AHK's objects guarantee a specific order for iteration which is immensely useful in a variety of situations.

A hash table on the other hand, unless if you've implemented some of your own rules on top of it, is unpredictable (though it is repeatable) with an effectively random iteration order. The only guarantee is that the same keys will come in the same order each time.

Please explain further what you mean by this.
AutoHotkey Arrays can have missing elements.

This destroys useful semantics of most array operations.
Your wording here is much stronger than I think it has any reason to be. AutoHotkey's arrays (I use this term loosely, they're still just the standard object type) can have missing elements, but in the case that you're using the object as an array you would not perform the operations that would lead to missing elements.

AHK developers, however few we may be, continually write code with arrays without butting up against "destroyed semantics" just because we can treat our data as an associative array rather than an indexed array. When we are interacting with list-style data we treat the object like a list, an indexed array. The interpreter isn't going to go breaking our indexes at random, if the index gets broken it's because we decided to use a well defined and documented operation that interacts with the object in that way.

I do agree that data integrity enforcement can be useful in some cases, but I think your point there should read more like this:

"AutoHotkey Arrays can have missing elements.

This makes ensuring data integrity more difficult than it should be in some cases."

I could probably sit here for a lot longer critiquing your readme but I don't necessarily have the time and I don't want to be overly critical. You're doing great! I just think you make a lot of unsubstantiated claims framed as truth. Not everything that AutoHotkey does is as good as it can be, but in many cases the developer(s) or community made a choice in a situation where there wasn't a strictly correct answer. Calling those nuances problems comes off in a somewhat aggressive manner; what you call a problem others may see as a strength and you're explicitly telling them they're wrong.

Instead of framing your project as "AutoHotkey Problems" vs "Facade Solutions", you might be much better off to frame it in terms of axioms. Don't make claims that a particular facet of the language is a problem just because you say so, define how you think it should be as an axiom for the project, show how AutoHotkey doesn't meet that requirement, then fill in how your library helps AHK to meet that. For example, https://gist.github.com/G33kDude/f4c65a ... -facade-md

And finally, take everything I just said with a grain of salt. Your project is your own and you should feel free to design it and document it however you want. Don't let some random guy on the net try to make decisions for you.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

24 Nov 2018, 13:47

GeekDude wrote:
24 Nov 2018, 13:08
Could you provide an example of verbosity in AutoHotkey that this library mitigates?

Code: Select all

Array := [1, 2, 3]  ; This is meant to represent an array you got from somewhere else.  It is not a part of the verbosity argument.

; without Facade
Total := 0
for _, Value in Array
    Total += Value
    
; Note that omitting brackets around branches and loops is known to be error-prone (see Code Complete 2), but it gives AutoHotkey more of a fair chance.

; with Facade
Total := Array_FoldL(Func("Op_Add"), 0, Array)
This is not an astounding improvement.

It is reasonable to wonder what a low-level functional programming construct is good for, but it puts the person answering the question in a similar situation to answering "What is addition good for?".

The primary improvement comes from encouraging a style of programming where you focus on describing how to process a single value then reuse that over and over (e.g. to build more complex functions, potentially at run-time, or as the body of the equivalent to a loop). This is as opposed to a programming style where you do a lot of explicit state manipulation and control flow. Those things are hidden behind functions and reused, like everything else. This also has a tendency to make things somewhat safer because it is easy to make mistakes when manipulating state or using control flow. If the code that does that is in one place and reused everywhere, defects tend to get noticed and corrected, and they only need to be corrected in one place.
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Facade Functional Programming Suite

24 Nov 2018, 14:13

I am not a programmer so OOP, functional, and procedural programming stuff are all new to me. I recently built a crappy v2 function evaluator that works more or less like a REPL, and while building it, my approach was to convert everything from infix to prefix form, which basically converts expressions to nested functions. Later on I wrote a few short functions to handle recursion/loops into array and objects, and a simple broadcast function that maps a function to objects/arrays (except I didn't call it that because I didn't know what I was doing). I also recently came across this thing called Lambda Calculus. It's over my head for sure, but still quite interesting, so yeah, thank you for sharing this!
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

24 Nov 2018, 15:25

I will respond to the other criticisms as a whole because they are all about AutoHotkey’s type system.

The decisions made with regards to AutoHotkey’s object model are bad because we know of better alternatives, and why they are better, and we knew this long before AutoHotkey was ever written (e.g. Smalltalk was released in 1972). Yes, these decisions need to keep context in mind. I did so.

There are other programming languages where objects are effectively dictionaries. The one most people would probably mention is Smalltalk, where literally everything is an object and literally everything (even the meaning of true and false) can be inspected and altered at run-time. That is setting a very high bar though. Python is a better example because, absent the mistakes, Python’s object model is similar to AutoHotkey’s. Python objects are literally dictionaries. However, Python does not consider foo['bar'] = 0 and foo.bar = 0 to be the same thing. The first will use the __setitem__ special method and the second will use the __setattr__ special method. Conflation is the right term for this mistake. The inside of the dictionary is confused with the outside of the dictionary. This makes AutoHotkey less powerful (it cannot make a distinction), not more powerful (there is nothing you can do because of this mistake that you could not do in a language that did not make this mistake).

The decision to use weak typing is bad. Again, it is bad because we know of better alternatives and why they are better. The problem with weak typing, which should not be confused with dynamic type checking, is that it makes detecting errors difficult, even at run-time. Most dynamically type checked programming languages are strongly typed (e.g. Smalltalk and Python). There are, unfortunately, examples of weakly typed programming languages in widespread use, like JavaScript, which spawned the infamous Wat video on this topic. Instead of an operation failing when an operand is of the wrong type, a weakly typed programming language will try to coerce the operand into a type that can work. The only time an error will be detected is when the programmer writes code to check the type manually or when the weakly typed programming language cannot come up with more ways to make sense out of nonsense. This usually results in silent corruption or a crash far from the point where the error actually occurred. All this is separate from AutoHotkey intentionally ignoring errors, by the way, which I should hope is obviously a bad decision.

AutoHotkey’s tacked on, barely an afterthought, OOP system is bad. Again, it is bad because we know of better alternatives and why they are better. Perl made the same mistake. When most types exist outside of, and in ignorance of, the object system, non-objects and objects do not work well together. To make things worse, most of AutoHotkey’s object-like constructs also exist outside of its object system. For example, a function object obtained from Func is not an object in the same sense that a user-defined function object (i.e. a class with suitable members) is. There are methods that exist on the user-defined object that do not exist on the built-in function object, and the built-in function object has no base class.

You went on to claim that the mistakes I have mentioned make AutoHotkey more powerful again. I have already covered why that is not true. You did not bring up the other problem that the problems you did bring up make worse.

For a dynamically type checked programming language to work well it must report errors (this should be obvious) and it must provide a reliable way to determine the type of any value or use a shared interface on all values that can exhibit a behavior (it need not do both, but most programming languages do). AutoHotkey does neither, and this is a major problem. There is no way to test the type of all values because built-in and user-defined types do not share a common type hierarchy. AutoHotkey does not use common interfaces to implement common behaviors. Detecting and reporting errors and writing code to work with different types is extremely difficult due to this decision.

I am aware of how to write a class that acts like a safe dictionary. I already did so long ago. It is HashTable, and Facade uses it.

HashTable’s page describes how AutoHotkey’s objects are unsafe. Facade’s page summarizes it. Undesirable behavior that occurs reliably is still undesirable.

Also, no, hash tables do not guarantee the same keys come in the same order. They very frequently will not do so if the hash table is mutated (this can lead to a resizing, and thus rehashing, in most implementations).

I have never written code that needs to operate on a dictionary’s keys in order. I know of a variety of ways to do it, but it would almost always indicate I was writing bad code. Dictionaries are for when you want to perform lookups efficiently by something other than consecutive integers. That usually implies that order is irrelevant. Other programming languages that do provide ordered dictionaries almost exclusively retain the order that keys were inserted, instead of ordering the keys alphabetically (which has no meaning for object keys, which are useful in graph traversal algorithms). That is because insertion order is the only key order that makes sense in the face of mutation.

Sparse arrays are useful in the unlikely situation where you are trying to represent a very large (too large to fit into memory) sequence where most of the values are the same. In every other situation they only cause problems. One does not expect an Array’s length to change if it is reversed or sorted, but it can if it can contain missing elements (specifically, leading missing elements in the reverse case and any missing elements in the sort case). And then there is the question of how one compares missing elements for the purpose of sorting. Writing code to work around this almost never desirable behavior for every comparison function used when sorting is no fun.

Actually using Arrays with missing elements is occasionally necessary in AutoHotkey. Specifically, it is necessary in the situation where you want to call a function that specifies defaults for some of its parameters variadically. If all parameters have defaults, you might need to use leading missing elements. If more than 1 parameter has defaults in a function with >= 3 parameters, you might need to use missing elements in the middle. These situations are, thankfully, rare. Those situations are the only reason Facade supports working with Arrays with missing elements.

As for strong wording, I have written a lot of AutoHotkey code, which has led to a lot of frustration. These libraries are an attempt to reduce that frustration by plastering over AutoHotkey’s problems so that I never again have to deal with them. I would have stopped using AutoHotkey long ago if it were not so useful to Windows system administrators. AutoHotkey’s good parts are its I/O facilities, not its programming language.
Last edited by [Shambles] on 24 Nov 2018, 17:20, edited 11 times in total.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

24 Nov 2018, 15:28

oif2003 wrote:
24 Nov 2018, 14:13
I am not a programmer so OOP, functional, and procedural programming stuff are all new to me. I recently built a crappy v2 function evaluator that works more or less like a REPL, and while building it, my approach was to convert everything from infix to prefix form, which basically converts expressions to nested functions. Later on I wrote a few short functions to handle recursion/loops into array and objects, and a simple broadcast function that maps a function to objects/arrays (except I didn't call it that because I didn't know what I was doing). I also recently came across this thing called Lambda Calculus. It's over my head for sure, but still quite interesting, so yeah, thank you for sharing this!
You might enjoy playing with and writing a toy Lisp interpreter. Ones with no error handling and few operations can be understood and written in about 1 or 2 days. Here is a link to one of the more digestible essays on the topic. That sounds very similar to what you were doing.

Anyone that can write a parser for AutoHotkey's syntax is deserving of the mantle of programmer. If you did that as a beginner, that is amazing!
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Facade Functional Programming Suite

24 Nov 2018, 17:22

Have you seen Object.ahk for v2? https://autohotkey.com/boards/viewtopic ... 37&t=57591 This separates data from interface, methods from properties. At the moment, it's theoretical, but having a dedicated data type should speed up AHK arrays when implemented.
geek
Posts: 1052
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: Facade Functional Programming Suite

24 Nov 2018, 18:41

I should probably apologize as I did not see how much thought and experience you had put into this before beginning to make my criticisms. I pointed out subjects that you had already examined and made rational decisions on, under the false assumption that you were unfamiliar with some of your alternate options.
[Shambles] wrote:
24 Nov 2018, 13:47
It is reasonable to wonder what a low-level functional programming construct is good for, but it puts the person answering the question in a similar situation to answering "What is addition good for?".

The primary improvement comes from encouraging a style of programming where you focus on describing how to process a single value then reuse that over and over (e.g. to build more complex functions, potentially at run-time, or as the body of the equivalent to a loop). This is as opposed to a programming style where you do a lot of explicit state manipulation and control flow. Those things are hidden behind functions and reused, like everything else. This also has a tendency to make things somewhat safer because it is easy to make mistakes when manipulating state or using control flow. If the code that does that is in one place and reused everywhere, defects tend to get noticed and corrected, and they only need to be corrected in one place.
It sounds like this style of programming is strongest for performing data processing. Given that most code I write is for API interaction, be it the Windows API or some Web API, do you think this approach is something that I would find helpful?
[Shambles] wrote:The decisions made with regards to AutoHotkey’s object model are bad because we know of better alternatives, and why they are better, and we knew this long before AutoHotkey was ever written (e.g. Smalltalk was released in 1972). Yes, these decisions need to keep context in mind. I did so.

There are other programming languages where objects are effectively dictionaries. The one most people would probably mention is Smalltalk, where literally everything is an object and literally everything (even the meaning of true and false) can be inspected and altered at run-time. That is setting a very high bar though. Python is a better example because, absent the mistakes, Python’s object model is similar to AutoHotkey’s. Python objects are literally dictionaries. However, Python does not consider foo['bar'] = 0 and foo.bar = 0 to be the same thing. The first will use the __setitem__ special method and the second will use the __setattr__ special method. Conflation is the right term for this mistake. The inside of the dictionary is confused with the outside of the dictionary. This makes AutoHotkey less powerful (it cannot make a distinction), not more powerful (there is nothing you can do because of this mistake that you could not do in a language that did not make this mistake).

The decision to use weak typing is bad. Again, it is bad because we know of better alternatives and why they are better. The problem with weak typing, which should not be confused with dynamic type checking, is that it makes detecting errors difficult, even at run-time. Most dynamically type checked programming languages are strongly typed (e.g. Smalltalk and Python). There are, unfortunately, examples of weakly typed programming languages in widespread use, like JavaScript, which spawned the infamous Wat video on this topic. Instead of an operation failing when an operand is of the wrong type, a weakly typed programming language will try to coerce the operand into a type that can work. The only time an error will be detected is when the programmer writes code to check the type manually or when the weakly typed programming language cannot come up with more ways to make sense out of nonsense. This usually results in silent corruption or a crash far from the point where the error actually occurred. All this is separate from AutoHotkey intentionally ignoring errors, by the way, which I should hope is obviously a bad decision.
I agree with much of what you are saying here, great points!

Allowing different spaces in an object to be accessed separately by the dot operator and the brackets operator is a good thing, and is something that python does much better than AutoHotkey. It is not clear from your original texts that this is what you are referring to, even in part, by conflation. I understood your position to be that the concept of using a dictionary-type-structure as the basis for the language's object system was itself flawed.

As far as weak typing, yes you are right. It made sense for what AutoHotkey was (text macros, hotkeys, mouse/keyboard manipulation, clipboard manipulation), and a lot of people still use it for just that. It does not make sense for AutoHotkey as a programming language in a larger capacity.

Ignoring errors, yes, is a bad design choice. This is a backwards compatibility problem to support code written before the exceptions system was implemented. This is being worked on in v2.
[Shambles] wrote:AutoHotkey’s tacked on, barely an afterthought, OOP system is bad. Again, it is bad because we know of better alternatives and why they are better. Perl made the same mistake. When most types exist outside of, and in ignorance of, the object system, non-objects and objects do not work well together. To make things worse, most of AutoHotkey’s object-like constructs also exist outside of its object system. For example, a function object obtained from Func is not an object in the same sense that a user-defined function object (i.e. a class with suitable members) is. There are methods that exist on the user-defined object that do not exist on the built-in function object, and the built-in function object has no base class.
Tacked on is accurate, barely an afterthought is a little dismissive to the work that Lexikos has put into the language/interpreter over the years, and bad is, I think, a slight overstatement. I don't claim that it's as good as possible, or that there's nowhere it could be improved. The goal as I understand it was to create an object system that worked with the rest of the intepreter, was dead simple enough for people who didn't have any idea what they were doing to use (leading to 1-indexed, all data exists in the same space so there's no question of how to access it, and many other oddities), and must be flexible enough to let the people who did know what they were doing to take advantage of it. Being good in a theoretical sense was not the priority over helping non-programmers to get up and running quickly. It meets the requirements it set out to even if those do not lend themselves well to, say, enterprise development.

You are right that the inclusion of separate objects that do not derive from the common base is a bit of an oddity. Function Objects, BoundFunc objects (which really ought to just be Function Objects), and RegEx Objects are admittedly bizarre. COM Objects also do not, but I think that's a rational decision given their capacity as an interface to remote systems.
[Shambles] wrote:You went on to claim that the mistakes I have mentioned make AutoHotkey more powerful again. I have already covered why that is not true. You did not bring up the other problem that the problems you did bring up make worse.
I am not sure what portion of my text you are referring to specifically, but my suggestion however weak is that it is more flexible than a language which does not offer the ability, not more powerful than a language that implements similar features in a more effective manner. I apologize for not making myself clear.
[Shambles] wrote:For a dynamically type checked programming language to work well it must report errors (this should be obvious) and it must provide a reliable way to determine the type of any value or use a shared interface on all values that can exhibit a behavior (it need not do both, but most programming languages do). AutoHotkey does neither, and this is a major problem. There is no way to test the type of all values because built-in and user-defined types do not share a common type hierarchy. AutoHotkey does not use common interfaces to implement common behaviors. Detecting and reporting errors and writing code to work with different types is extremely difficult due to this decision.
This is unfortunately very accurate. As I mentioned above v2 is working on the error reporting side of things. I'm not sure if it's also working on type determination, but I sure hope so.

Using a shared interface on all values is unlikely to ever happen with AHK for better or worse (probably worse). From a macros-and-automation standpoint it's largely unnecesary, but from a pure programming standpoint it sure would be nice.

Writing code to work with different types is pretty difficult in AHK, yes. This comes up when writing wide-reaching libraries like the one you're working on here, but in my experience rarely comes up in day-to-day usage of the language. This isn't to say it's not bad, just not often a nuisance.
[Shambles] wrote:I am aware of how to write a class that acts like a safe dictionary. I already did so long ago. It is HashTable, and Facade uses it.

HashTable’s page describes how AutoHotkey’s objects are unsafe. Facade’s page summarizes it. Undesirable behavior that occurs reliably is still undesirable.
Again I must apologize, your hash tables are much better thought out and implemented than I initially assumed.

I agree that AHK's objects' indexing (and other features) behave undesirably in many cases. I would likely not have said anything on that if you had written "undesirable" in the readme rather than "unreliable".
[Shambles] wrote:Also, no, hash tables do not guarantee the same keys come in the same order. They very frequently will not do so if the hash table is mutated (this can lead to a resizing, and thus rehashing, in most implementations).
I had considered whether to write more or less about that, and it seems I missed the mark as I often do. The unwritten assumption of my text was that the user was not triggering any kind of rehash between iterations. Guarantee was too strong a word.
[Shambles] wrote:I have never written code that needs to operate on a dictionary’s keys in order. I know of a variety of ways to do it, but it would almost always indicate I was writing bad code. Dictionaries are for when you want to perform lookups efficiently by something other than consecutive integers. That usually implies that order is irrelevant. Other programming languages that /do/ provide ordered dictionaries almost exclusively retain the order that keys were inserted, instead of ordering the keys alphabetically (which has no meaning for object keys, which are useful in graph traversal algorithms). That is because insertion order is the only key order that makes sense in the face of mutation.

Sparse arrays are useful in the obscure case where you are trying to represent a very large (too large to fit into memory) data set where most of the values are the same. In every other situation they only cause problems. One does not expect an Array’s length to change if it is reversed or sorted, but it can if it can contain missing elements (specifically, leading missing elements in the reverse case and any missing elements in the sort case). And then there is the question of how one compares missing elements for the purpose of sorting. Writing code to work around this almost never desirable behavior for every comparison function used when sorting is no fun.

Actually using Arrays with missing elements is occasionally necessary in AutoHotkey. Specifically, it is necessary in the situation where you want to call a function that specifies defaults for some of its parameters variadically. If all parameters have defaults, you might need to use leading missing elements. If more than 1 parameter has defaults in a function with >= 3 parameters, you might need to use missing elements in the middle. These situations are, thankfully, rare. Those situations are the reason Facade even supports working with Arrays with missing elements.
These are very valid criticisms which I generally agree with. AutoHotkey's objects just weren't designed for such tasks, and AutoHotkey wasn't built for efficiency. It's not the right tool for these tasks and it's annoying to use for them in situations where you have to.
[Shambles] wrote:As for strong wording, I have written a lot of AutoHotkey code, which has led to a lot of frustration. These libraries are an attempt to reduce that frustration by plastering over AutoHotkey’s problems so that I never again have to deal with them. I would have stopped using AutoHotkey long ago if it were not so useful to Windows system administrators. AutoHotkey’s good parts are its I/O facilities, not its programming language.
You are right. Given that, why put your effort into improving the language features instead of improving the I/O facilities of another language? Is it library support, interoperability with existing codebases of your own, to appease other administrators, or some other reason?

I appreciate your strong viewpoints and candid responses even if we don't agree on everything. This thread probably isn't the best place for this type of discussion so I apologize for bringing it up.

Okay, back to code. I wanted to get started with your library so I decided to try my hand at a text manipulation algorithm, though I think I have a few misunderstandings on how to best use the library.

I've built this script to perform a barebones ROT13 algorithm, though it's missing the critical behavior of detecting characters outside the alphabetic range.

Code: Select all

SubA := Func_Flip(Func("Op_Sub")).Bind(Asc("a"))
AddA := Func("Op_Add").Bind(Asc("a"))
Add13 := Func("Op_Add").Bind(13)
Mod26 := Func_Flip(Func("Math_Mod")).Bind(26)
RotChar := Func_Comp(Func("Chr"), AddA, Mod26, Add13, SubA, Func("Asc"))
RotString := Func_Comp(Func("Func_Apply").Bind(Func("Op_Concat")), Func("Array_Map").Bind(RotChar), Func("StrSplit"))
MsgBox, % %RotString%("hello")
I tried to write some code to detect if a character was in the alphabetic range so I could chain it to Func_If such that it would perform RotChar on characters in the range and pass the character through using Func_Id if not. My code unfortunately didn't work.

Code: Select all

GtA := Func("Op_Le").Bind(Asc("a"))
LtZ := Func("Op_Ge").Bind(Asc("z"))
IsAlpha := Func_And(GtA, LtZ)
MsgBox, % %IsAlpha%(96)
This gives me the exception "Argument is an Object". It appears that when I run Func_And with a single predicate it behaves as I expected, but when I run it with multiple predicates it fails.

Also, either I'm misunderstanding the library or this isn't one of those tasks where it decreases verbosity. Compared to my more traditional implementation of the same ROT13 behavior, the function composition version hides the logic among a lot more fluff.

Code: Select all

Out := ""
for k, v in StrSplit("hello")
	Out .= Chr(Mod(Asc(v) - Asc("a") + 13, 26) + Asc("a"))
MsgBox, %Out%
Programming with function composition certainly requires a different head space than most of the code I've written in the past. I definitely plan to continue investigating how I might fit it into my workflow.

There have been community members before who tried to build function-composition-facilitating libraries before (though I can't remember any particular names) and none of them have ever gotten anywhere close to where you are now. Your code is very sound both in theory and in implementation :clap:.
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: Facade Functional Programming Suite

24 Nov 2018, 18:47

[Shambles] wrote:
24 Nov 2018, 13:47
GeekDude wrote:
24 Nov 2018, 13:08
Could you provide an example of verbosity in AutoHotkey that this library mitigates?

Code: Select all

Array := [1, 2, 3]  ; This is meant to represent an array you got from somewhere else.  It is not a part of the verbosity argument.

; without Facade
Total := 0
for _, Value in Array
    Total += Value
    
; Note that omitting brackets around branches and loops is known to be error-prone (see Code Complete 2), but it gives AutoHotkey more of a fair chance.

; with Facade
Total := Array_FoldL(Func("Op_Add"), 0, Array)
saying "AHK is verbose" is deceiving. first of all you've omitted your "Op_Add()" func which is required for your example to run. but still all you've provided is the functional programming fold() func. ANY language that doesn't provide these functional programming funcs built in would be "verbose" in that case. not just AHK. you should just say, "procedural programming is verbose" instead.

now whether verbosity is bad or good is another question altogether. i tend to prefer more readable code rather than more compact code. 90% of programming is reading and comprehending and editing

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

Re: Facade Functional Programming Suite

24 Nov 2018, 19:02

iseahound wrote:
24 Nov 2018, 17:22
Have you seen Object.ahk for v2? https://autohotkey.com/boards/viewtopic ... 37&t=57591 This separates data from interface, methods from properties. At the moment, it's theoretical, but having a dedicated data type should speed up AHK arrays when implemented.
I had not. As far as I knew the current status of v2 was basically v1, made incompatible, with error reporting, closures, and an improved GUI library (and those changes are relatively recent). I had not heard that a type hierarchy for exceptions was being discussed, nor had I heard that Object's interface-contents conflation might be fixed. I do wonder how they make closures work without tracing garbage collection, without leaking...

This all sounds nice, but I will not use it until it is officially released. I have little faith that it will be very good. The developers do not listen to their users (or more accurately, they tell them that they are wrong even when they are right). I do expect it to not be as bad as v1 because any error reporting is likely to be better than none and closures are nice.

Years ago, when v2 was just v1 made incompatible, I wrote a library called Plaster. It used knowledge of how Array and Object are instantiated, memory peeking hacks, some tables, and some common interfaces to make good error reporting possible (not easy, just possible). Specifically, it would complain if you tried to read Array indexes or Object keys that did not exist, it could tell you about the signature of any AutoHotkey procedure (even built-in methods), and it could convert any type into a meaningful string representation. It was not anything special. This is behavior that users of almost every other programming language take for granted. You just miss it terribly when you are used to it and it is not there any more.

I had even written code atop this library. I was working on a functional programming library, Composer, to remove the thorn in my side that is too many, too weak, control flow constructs and the excessive use of magic variables.

Then BoundFunc function objects were added.

They were a little like the curried functions in Composer, only less convenient. But there was a problem more serious than the inconvenience of having to pass all arguments to be closed over (bound) at once.

BoundFunc function objects did not have the same interface as every other AutoHotkey function object at the time. Plaster depended on that common interface. Amazingly, a BoundFunc function object, often returned by a Bind(Args*) method on a function object, does not have a Bind(Args*) method!

I was frustrated. I thought this might just be thoughtlessness. Maybe they were distracted or tired when they had the idea. So I complained on the forums.

I had already learned that you cannot expect good taste or reason. I had already had a discussion about the merits, or lack thereof according to the developer, of consistency in the class names returned by v2's proposed Type function. I was more open to using v2 back then. I had seen other people argue with the developers about similar problems. I had learned to expect to be shot down and be told I do not know what I am doing. So I wrote a long essay rattling off all the problems I could recall from my past year of usage, how those problems should be fixed (to preempt people telling me to not complain if I offer no better alternatives), and preemptively shooting down any arguments I had already heard or could predict (e.g. the "ease of use (in one of the most user hostile languages outside Brainf*ck)" and "we care about efficiency (so you can't have nice things) until we don't (which is why AutoHotkey is one of the few programming languages where whitespace affects efficiency)"). It was met with the one response from the developers that I did not expect, silence. There were responses, but none from the people that could actually fix things. Well played...

You might suspect that I was a little annoyed.

Facade is what became of Composer. It is intentionally written without depending on any hacks like Plaster used. It assumes as little as possible about what will work on the types it uses. Its error handling will necessarily be worse as a result. It depends as much as possible on things I maintain. I do this in the hopes that future changes will not break it, and intentionally breaking it will be as painful for the developers as possible because of how much of other peoples' code will be broken.

So although v2 might fix a lot of my complaints, I will not be using that moving target. I will only use it when changing it becomes uncomfortable for the developers.

I fixed my complaints myself since I could not get any traction elsewhere. No telling me to put up or shut up.

I am also pretty sure they do not want my feedback. My feedback is pretty simple. Make everything as consistent as possible (e.g. put everything, including built-ins, in the same type hierarchy and start using shared interfaces for everything), avoid conflating concepts (e.g. arrays and dictionaries have no business being the same type), and if you do not know how to do this, rip things off from someone that does (e.g. Python is not a bastion of virtue (see the handling of mutable defaults for one of Python's big mistakes), but you could do worse than start there). Really, I just wish the language in AutoHotkey would be replaced with something widely used. JavaScript and Lua have a lot of problems (variables that are global by default, Lua uses 1-based indexing, etc. etc.), but V8 and LuaJIT are at least efficient and stable, and if you do not like JavaScript or Lua, there are a lot of better programming languages that compile to them.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

24 Nov 2018, 21:37

GeekDude wrote:
24 Nov 2018, 18:41
<lots of stuff>
I do not want my replies to keep just getting longer, so I will try to avoid long quotes.

Functional programming is a kind of declarative programming. I consider referring to it as that to be almost overselling it to the point of it being misleading. Prolog is a lot closer to truly declarative programming (tell the computer what you want to happen and the computer figures out how to do it) than functional programming. Functional programming is a lot closer to imperative programming without mutation (construct new things instead of changing existing things) than some automated reasoning system. In any case, anything with side effects tends to work poorly with most declarative programming (with the possible exception that push dataflow seems to work well with I/O) and that is also true for functional programming. That means declarative programming is mostly if not exclusively good for processing. As for why anyone might want to use functional programming in AutoHotkey, it is useful for parsing text, and sysadmins do a lot of parsing text.

There is this strange, and rather infuriating, assumption that people who only do programming 'on the side' are undeserving of a pleasant programming language to work with. Most languages sysadmins deal with look like they were demonstrations of what not to do in a computer science course. The bad decisions made in AutoHotkey's design did not make sense because it was used for 'unimportant' (read: unworthy) things. Hate on that admin all you want, wish them to Backtick Hell (Bash scripters know what I mean), but you will be sorry when your server keels over and you do not have them to kick around any more. The bad decisions were just plain bad!

If you ever need to install the right driver bundle on several hundred machines, based on the contents of a CSV file containing their MAC addresses, you will be glad that AutoHotkey exists, even if it simultaneously makes you hate it for existing. System administration is weird like that. There is a reason The Bastard Operator from Hell stories exist. They are based on the experiences and power fantasies of people stuck in that profession.

I am thankful that Lexikos added objects for one reason: it made data structures possible in AutoHotkey. I only wish it had been done better.

The problems I brought up are not about theoretical purity. They are about making things work correctly. Even some of the unlikely scenarios, like needing to preserve the case of string keys, has mattered in code I have written. For example, command line arguments are case sensitive (/P and /p might mean very different things), so if you are going to store the command line argument as a key and its value as the value in a dictionary for processing, it really helps if string case is preserved! By the way, I wrote a tutorial about this. I have also written shoddy keyboard layout analysis code that needed to care about the case of characters because it implied when the Shift key had been pressed. The gist is that a data structure should never implicitly change a value. If I want the keys case folded, I will case fold them myself (tip: use uppercase to correctly handle Greek sigma).

And on that note, giving beginners badly designed programming languages "because they are easy to understand" is a terrible idea. I certainly hope you would not teach children to read by using examples of badly written text messages instead of books. Why should something almost infinitely more difficult be treated with less concern?

"It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration." -- Edsger W. Dijkstra

I learned to program with Commodore BASIC and GW-BASIC, and I know exactly what Dijkstra was talking about. I learned to program in the sense that I learned how to tell a computer to do something. I did not learn to program well (i.e. how to tell a computer to do what I intended it to do or do something reliably) until many years later, and most of that involved unlearning bad habits I had developed in BASIC (that is "BASIC with line numbers" or as the Computer Contradictionary describes it "shit with icing", not QBASIC or Visual Basic). Please, stop hurting programming!

There is nothing special about a "macros-and-automation standpoint" that makes it somehow less important for values to behave consistently. There is nothing about inconsistency that makes AutoHotkey "easier" for beginners (quite the opposite!). You are, however, probably correct that the developers are unlikely to ever use shared interfaces for most behaviors.

The problem comes up in day to day usage, unless your day to day usage is strictly limited to remapping keys statically for video games. Then you can just fill out a form. Once things progress to "I read in a file and do some stuff based on what it says", you are probably going to hurt yourself. It is just a question of when, how, and how much.

On "undesirable" vs "unreliable" when describing the problems with Object (a dictionary)... I believe "unreliable" is accurate. If I read in two strings (e.g. those command line flags again) that differ only in case and I use them as keys that have different values, one will clobber the other. The one that survives will be the one that happened to be read in last. That seems pretty "unreliable" to me, in the same sense that race conditions in defects involving multithreading are usually described as "unreliable" (and "undesirable") even when their mechanics are fully understood, and are similar enough to this scenario to be relevant. Nothing is good about this situation. Data structures should not implicitly change their contents.

As an aside, I am (mostly) tolerant of AutoHotkey being case-insensitive. If Object was only used for the interface of objects and there was some alternative case-preserving dictionary provided standard, I could stand it. As it is, if you want a dictionary-like thing you either have to use Object, which does not work right for this purpose, or you have to cook your own class, which is what I did.

On hash tables and key order necessarily being preserved across iterations... No, really, it makes sense for a hash table to never report keys in a predictable order. My own implementation might report the keys in a different order if you explicitly Get(Key) one (note: not a destructive / mutating operation). This is a common optimization called chain reordering. It makes future lookups of the same key faster, optimizing a common access pattern. If you need the keys in a particular order, that order is not insertion order, and you are using a 'normal' dynamically type checked programming language (one that can mutate things), you need to store those keys in a ordered data structure. Facade includes functions to do that (you probably need something likeArray_Sort(Func("Op_Lt"), Ht_Keys(HashTable)), then iterate over that while operating on HashTable).

As for why not just improve the I/O facilities of another language... Have you ever tried to read and understand AutoHotkey's source code? Several files are more comment than code, and those comments are not comforting. I did not learn much, but I did become completely convinced that I never wanted to have to understand how it worked. I had rather the AutoHotkey maintainers take care of maintaining the I/O facilities than take that upon myself. There are more of them than there are of me anyway.

You asked what keeps me using it. What is good about AutoHotkey is the I/O facilities. I took issue with their use of goto labels in the past, but that is no longer necessary. The GUI support is still pretty bad in v1, but it looks better in v2. It still needs a grid layout manager, last I heard. Getting data in and out of AutoHotkey is pretty easy. Calling into most tolerable high-level languages (e.g. when a key combination is pressed) is not pleasant. AutoHotkey makes that easy. AutoHotkey scripts are also very easy to convert into an executable bundle with one or more executables to make automatic installers for things like drivers, which is a godsend for sysadmins. Basically, everything is really good but the programming language, which is really terrible.

You found a defect in Func_And(Preds*). I apologize, but I am not at all surprised. I expect to find a lot of defects as I rewrite the error handling, just as soon as I figure out how I should rewrite the error handling.

The responsible code looked like this: Preds[Index](Args*)

It needed to be this, for reasons that I do not understand: Preds[Index].Call(Args*)

I have uploaded a fix.

There appears to be nothing wrong with your understanding of how the libraries work, but there is a misunderstanding of how they are intended to be used. You constructed almost all of your code at run-time when you could have just written the code directly in your source. Higher order functions are not intended to eliminate source code. They are intended to allow functions to be reused easily.

I believe something like this would have been more natural, though not significantly shorter than the imperative equivalent.

Code: Select all

ROT13(Char)
{
    return Chr(Mod(Asc(Char) - Asc("a") + 13, 26) + Asc("a"))
}

MsgBox % Op_Concat(Array_Map(Func("ROT13"), StrSplit("hello"))*)
Last edited by [Shambles] on 24 Nov 2018, 22:45, edited 2 times in total.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

24 Nov 2018, 21:57

guest3456 wrote:
24 Nov 2018, 18:47
saying "AHK is verbose" is deceiving. first of all you've omitted your "Op_Add()" func which is required for your example to run. but still all you've provided is the functional programming fold() func. ANY language that doesn't provide these functional programming funcs built in would be "verbose" in that case. not just AHK. you should just say, "procedural programming is verbose" instead.

now whether verbosity is bad or good is another question altogether. i tend to prefer more readable code rather than more compact code. 90% of programming is reading and comprehending and editing
I did not omit anything and nothing was deceiving. The task was to compare stock AutoHotkey to using Facade. Op_Add is part of Facade. The code for Array_FoldL was also not shown, and Facade includes vastly more than that.

There is nothing inherently unreadable about functional programming. You can trivially write bad code in it. Church encoding and SKI combinator calculus should give you some great ideas for obfuscating code. On the other hand, good old imperative self-modifying assembly is also really great for obfuscating code. We should instead concern ourselves with how easy it is to write good code with some constructs.

So long as you do not need to perform I/O and you are not trying to write bad code, functional code will tend to be clearer than the imperative equivalent. You will have to learn what the constructs mean, just like you did with imperative programming constructs. Functional code is primarily concerned with what transformations are to be made, not resource handling or how those transformations are to be made, and there is no "spooky action at a distance" from mutation.

I am not deluded. I/O is a necessity. However, keeping most of your code free of side effects definitely improves how easy it is to understand and reuse.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

19 Dec 2018, 21:29

I have just finished the error handling rewrite. Facade functions now validate their arguments and report errors that can only be detected 'deeper in'.

Facade's exceptions reveal
  • the type of error
  • the function it occurred in
  • which argument was at fault, if applicable
  • the precise nature of the error
  • a representation of the type (if a type error) or value (if a value error) at fault, in most cases
There are still errors Facade cannot detect, like calling a non-variadic function with too few arguments and trying to access a member that does not exist. AutoHotkey makes detecting these errors impossible. Still, should one of these errors occur, it is likely that code written atop Facade will throw an exception very close to the defect.

Reporting the function the error occurred in is very helpful because AutoHotkey normally only shows the line, and there is usually more than one function call per line.

Some other user-visible changes have been made.

All my libraries have more consistent documentation.

Facade now depends on my type checking library and the FacadeTypes library is now called Validate (and does more than check for type errors). I know these changes do not seem beneficial to users, but they need to know the former to install Facade and they can delete the unneeded FacadeTypes.ahk file if they used previous versions. Be sure to use current versions of the type checking and hash table libraries. Some defects were corrected in the former and error reporting was improved in the latter.

Math_Rem(X, Y) was added for the remainder function, which is what AutoHotkey calls Mod(X, Y).

Math_RoundEven(X)’s unbiased rounding is now the norm for Math_Round(X, N), so Math_RoundEven(X) has been removed.

Math_Int(X) has been renamed Math_Integer(X) in an attempt to be more consistent with most of AutoHotkey.

Facade now uses 0-based array indexing throughout. Do not panic! This is just an illusion maintained for the sake of the programmer’s sanity. The underlying arrays are normal 1-based Arrays compatible with the rest of AutoHotkey.

Array_Index(Array, N) was added for when you really do need to use a calculated array index.

Array_Slice(Array, Start, Stop) was added to perform array slicing. It uses half-open intervals and indices clamped to bounds like most implementations, for good reasons (explained in Design.txt).

Ht(Items*) was added as a way to call the HashTable constructor. It is primarily useful because it is a function and it is shorter than calling HashTable’s constructor the usual way.

If you discover any problems with Facade’s design or implementation, please report them.
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Facade Functional Programming Suite

19 Dec 2018, 23:20

This is really good stuff. I'm too used to AutoHotkey's ways of doing things, but I'll be looking at your implementation details for ideas. By the way, having proper boundfuncs is really helpful.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

27 Dec 2018, 05:49

I have updated the Type Checking and Facade libraries.

The only breaking changes are in Facade:
  • Func_Reparam(Func, Positions) was renamed Func_Rearg(Func, Positions)
  • Func_Fork(G, F, H) had its parameters rearranged to Func_Fork(F, G, H)
Func_Rearg(Func, Positions) makes more sense in the presence of variadic functions, where it can rearrange the arguments inside a parameter. rearg(func, indexes) is also what Lodash calls it.

Func_Fork(F, G, H)’s parameter order now matches the order used for the S' combinator in mathematics. It was originally based on J’s notation.

Defects were corrected and code was improved in both sets of libraries.

The most significant changes are in the documentation. In Facade’s README, I included the mathematical basis for several combinators and their notation was made consistent with mathematics. Facade’s Design.txt has been almost completely rewritten.

Those interested in implementation details might find reading Design.txt helpful. Knowing the intention behind the design and why things work as they do can help with understanding how they work. Some of the information (e.g. the exception hierarchy used) might be difficult to reverse engineer from the source. It is not necessary reading for using the libraries. None of them throw exceptions that are intended to be caught (they all indicate defects in the programmer’s code).

I hope to eventually include a library for singly linked lists and a library for Lisp-like even streams. The list library could provide an efficient functional alternative to a stack (like Array’s Push(Args*) and Pop()). The stream library could provide an efficient functional alternative to AutoHotkey’s enumerators or the generators or comprehensions in many other programming languages, with the potential to ‘go back in time’. It will take some time for me to figure out if these ideas have merit, how to best implement them (including error handling), and how to best integrate them with the rest of Facade. I do not expect the existing libraries to change much, but I could be surprised. I will be on the lookout for anything not adequately generalized in the existing libraries as I work on these.

I hope you all have a happy New Year!
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

13 Jun 2019, 06:26

I believe I have finished an update to several of my libraries: Everything should be up to date except for Facade’s design document. It has not been updated for some time. I have been putting that off because the design kept changing. This should not interfere with anyone’s attempt to try out the libraries.

The changes are too numerous to list or for me to remember.

Defects were corrected.

Facade was refactored to eliminate redundant code. If you have used an older version, you should delete its files before installing the new version.

Facade no longer requires HashTable. HashTable is still maintained. It might be of use to people who need a dictionary type but do not want to use Facade. If this does not describe you, you should delete its file.

I made some changes based on feedback.

Facade’s new dictionary type is ordered. It should be almost as efficient as HashTable (it is effectively a hash table of key-index pairs, where the indices are for an array of items and tombstones). This change is almost invisible to the rest of Facade, and that is intentional. I still believe that depending on the order of items in a dictionary almost always indicates that you are writing bad code. That is why Facade’s comparison functions ignore the order of items. I have found some (very) obscure uses for it, which is why I agreed to make this change.

There is now an “Intention” chapter in the documentation that acts as a brief orientation to Facade. Although it contains a cursory explanation of functional programming, it is primarily concerned with how Facade differs from other functional programming libraries and how it is intended to be used. It is not intended to be a tutorial. I intended it to stop people from hurting themselves with the libraries.

Some of the additions might seem odd.

The List library is intentionally limited. It is adequate for acting as a functional replacement for Array’s stack methods. This is an important part of providing a better standard library.

The Random library might seem like an especially poor fit for a functional programming suite. However, Random_Shuffle(Array) completes the replacement of AutoHotkey’s Sort command. It was also very useful for testing Array_Sort(Pred, Array) and predicates written for it. The Random([Min, Max]) and RandomSeed(Seed) functions are backported from AutoHotkey v2.

At this point, Facade seems to be an almost complete replacement for AutoHotkey’s standard library, except for the I/O procedures, which I believe are acceptable (except for the GUI commands).

I am not entirely comfortable with the design of the String library, but it is unclear to me what should be done. Other than what is there, I almost exclusively use regular expressions and occasionally StrSplit. I do not have the stomach to try to replace AutoHotkey’s regular expression design, though it has no error reporting and redundant members. StrSplit works well enough and is occasionally more terse than using regular expressions would be. I need to work with strings heavily, but I no longer enjoy it now that Unicode has replaced ASCII, especially when the programming language provides no way to work with extended grapheme clusters (what a human thinks of as a character).

Please do not ask for a tutorial. Writing and maintaining the documentation is already a heavy burden. It is also already a long read. There are about 200 functions, and each one is documented with a paragraph that is as concise as I can make it. Use cases and examples are included when I believed anything was not obvious. There are many existing resources that explain functional programming.

Please do not ask me to play code golf. I have already demonstrated that functional code tends to be shorter than the equivalent imperative code. Look at those examples if you need convincing or do your own research. Terseness is also not the sole measure of a paradigm’s worth.

I am interested in feedback on Facade’s design and bug reports.

If anything Facade-specific is unclear, ask and I will try to explain it.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

29 Jun 2019, 04:24

These libraries have been updated again: Several bugs were fixed. Some were various problems with inf and nan values. Others were not ensuring types are the same (not just collection contents) before considering values equal or ordered.

Op_Bin(X) is now about 10x faster, not that it was likely to be a bottleneck for anyone.

Func_FromDll(NameOrPtr, Types*), a requested function, was included.

The ConcatMap functions became ConcatZipWith functions. These are strictly more powerful. For sequences (not dictionaries), mapping is just zipwithing over one sequence.

I am still working on updating the design document.
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: Facade Functional Programming Suite

30 Jun 2019, 14:49

@Shambles, thank you very much for this prodigious accomplishment. I can't begin to imagine how many days and hours you've spent on it so far.
Regards,
burque505
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: Facade Functional Programming Suite

30 Jun 2019, 16:51

Spectacular work and efforts! I've read every post in this thread. It was pure delight.

I consider myself a beginner and, unfortunately, ahk is my first programming language. I hate it's too versatile, to the point of being confusing. And yes, it does things "to make it easy" for beginners, but it's actually bad.

I'll look into this library and determine if I can make use of it in my projects. As I understand, it would be beneficial, however my limited skills might impede me from using it.

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.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

04 Jul 2019, 01:17

While working on the design document, I noticed several places where Facade was not as consistent as it could be and its names were not as good as they could be. Making yourself aware of your poor design decisions is one of the reasons for maintaining a design document.

I renamed the IsNull functions to IsEmpty functions and included Is<Type> and IsEmpty functions for the Array and Dict types. Array_IsArray(Value) and Stream_IsEmpty(Value) are not trivial, and the other Is<Type> functions keep you from having to include a global variable in your scope so that you can use Is(Value, Type) (Is(Value, List), Is(Value, Stream), and Is(Value, Dict) should still work).

I also renamed Func's Adverse to FailSafe. Its name came from J, which is not well known for using intention revealing names, where each function can be associated with an inverse and 'adverse'.

I improved Facade's user-level documentation in other minor ways (e.g. more warnings about where posets can cause problems).

I would still like to find better, short names for Func’s left and right hook combinators. Unfortunately, they are very abstract and are not obviously related to other functions (they are implemented atop ApplyRespWith). The name "hook" comes from J, and it is inspired by the shape of the data-flow graph. J's name came from heavily using hooks. In J there are unary (S combinator) and binary (similar to the D combinator) hooks, so J has no equivalent to the right hook, as far as I know. I do like the 'left' and 'right' part of their names in Facade because it matches the kind of fold they are usually used with. Feel free to share suggestions.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 124 guests