Facade Functional Programming Suite

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
Chunjee
Posts: 1400
Joined: 18 Apr 2014, 19:05
Contact:

Re: Facade Functional Programming Suite

22 Jan 2020, 11:12

burque505 wrote:
22 Jan 2020, 09:46
Using AutoHotkey is fun and frequently rewarding, but it does not pay my bills.
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: Facade Functional Programming Suite

22 Jan 2020, 11:41

Redux: My LIB folder now looks like this. I did read the installation instructions, but got confused. So everything is now in a LIB folder.
Lib_contents.PNG
Lib_contents.PNG (13.06 KiB) Viewed 4141 times
Now I'm getting the following syntax errors from my little script:

Code: Select all

#Include <Dict>
ChangoDict := Dict("one": 1, "two": 2)
msgbox Dict_GetKey("one", ChangoDict)
ExitApp

Code: Select all

AutoHotkey-Facade\Chango.ahk (7) : ==> Missing ")" before ":"
>Exit code: 2    Time: 0.1536
Could I trouble you for an example of Dict creation?

Regards,
burque505
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Facade Functional Programming Suite

22 Jan 2020, 11:59

dict is a function, ure trying to apply ahk's object syntax. i dont know how dict works, but obviously thats the wrong way to call it
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

22 Jan 2020, 13:01

robodesign wrote:
22 Jan 2020, 07:06
I will read the documentation. I was not aware that the main documentation is done.
The Lessons Learned file goes into why I maintain the Design document. By defending why I did something, I often learn when I made a mistake. By recording why I did something, I prevent future maintenance (including that by myself) from fowling it up. I also try to use it to give credit where it is due (e.g. Facade's Design document's Func section records where all the combinators came from). The Design document isn't intended for people using the software, though it might be of interest to 'power users' looking for unusual ways to use it because it might hint at such uses.
robodesign wrote:
22 Jan 2020, 07:06
I am working on Quick Picto Viewer , I do not know if you have seen its associated thread.

https://www.autohotkey.com/boards/viewtopic.php?p=296853

And for this project, I am working with potentially large arrays: sort, remove duplicates and so on. The arrays are file details or lists of files. Would using Facade help make it faster?

My main concerns are: performance and ease of use [to transition to Facade].
I am afraid that I am not familiar with many projects written in AutoHotkey.

I mostly use it to remap keys in games and occasionally add rapid fire because modern games are often so poorly designed (in the 80s and 90s most PC games had built-in key remapping and games that needed rapid fire came with it) and to automate system administration tasks because Windows software is often so poorly designed (in the 1970s most software designed for businesses and schools were designed to be installed and managed centrally with minimal fuss (none of this clicking through wizards on each machine nonsense)). That means the code is often not reusable because it is intimately tied to the software it automates. Facade is an exception. The code it contains would normally be part of the programming language.

As for can Facade "make it faster", that depends on what you mean.

Facade can probably make you, the human, faster at writing such code because it reduces the code you must write. Facade has powerful array sorting algorithms (it can sort totally ordered sets in ascending and descending order using arbitrary criteria provided by a ≤ predicate and comes with predicates suitable for sorting arrays of arrays and sorting in natural sort order) and deduplicating algorithms (that use arbitrary criteria provided by a function that extracts values to compare by).

Facade cannot make your program, the code, faster because any abstraction that does not get compiled to literals can only add overhead. Minimalist, custom code will always be most efficient. If you insist on always having the most efficient execution you will be writing assembly by hand for the rest of your days, which will make you, the human, very inefficient. It would seem this is poorly understood by modern programmers. There is another conversation earlier in this thread by someone asking if Facade can make array processing faster (as in make it execute faster).
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

22 Jan 2020, 13:05

Chunjee wrote:
22 Jan 2020, 08:33
I would like to try this but don't have a project that I think would fit well. A tutorial would go a long way.
Literally any project should fit well. Facade contains basic building blocks for general programming. No part of it is application-specific.

Unfortunately, I am having trouble finishing the existing documentation on my plate, and adding more is not likely to help. Since the documentation provided is apparently inadequate, it would help if you asked about what you are having trouble understanding. I will try to explain as best I can.
User avatar
Chunjee
Posts: 1400
Joined: 18 Apr 2014, 19:05
Contact:

Re: Facade Functional Programming Suite

22 Jan 2020, 13:29

I have quicksort and Facade doesn't crawl websites.

I think this is better suited for a math heavy project like the 8 Queens problem example which sadly is over my head.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

22 Jan 2020, 13:57

@burque505, @Chunjee
burque505 wrote:
22 Jan 2020, 09:46
Using AutoHotkey is fun and frequently rewarding, but it does not pay my bills.
It can help pay the bills if you are a Windows system administrator at a business or school. The alternative is clicking through wizards on several hundred to several thousand machines to install software or make trivial configuration changes.



As for installing Facade, there is a section for that in the README linked to by a nice collapsible table of contents. It is very short and very explicit. AutoHotkey's documentation explains how to install libraries.

Like it says, you only need to put the *.ahk files in your library directory (not, for example, the *.md or *.txt files, which I notice you have copied over). Having those files in your library directory should be harmless enough, I suppose.

You do need to install the Type Checking library's files (this is mentioned in the installation instructions) to stop it from complaining about the missing IsType, IsFuncObj, and Type functions, which I see you have figured out.

The Type Checking library is not part of Facade because it can be used without Facade. One particularly good reason for it not being part of Facade is because Facade is built on top of it. It contains some hairy, but vital code, written in a peculiar way (designed to be... unpleasant, for the AutoHotkey developers to break, and remove any doubt such an act would be intentional), to ensure Facade does not suffer the same fate that Composer did.

If you read Dict's documentation, near the top, it explains that Dict uses the concept of items represented as arrays of 2 elements.

Correct code for your example would look like this:

Code: Select all

ChangoDict := Dict(["one", 1], ["two", 2])
msgbox % Dict_Get("one", ChangoDict)
Auto-inclusion makes explicitly including the Dict file unnecessary.

Dict(Items*) is indeed a normal ('factory') function, and your syntax error was due to trying to use AutoHotkey's 'Object syntax'. No one can make their functions use that syntax, and I would not want to because it turns out that representing Items as Facade does is more useful.

The function to read a key is Dict_Get(Key, Dict), not Dict_GetKey(Key, Dict).

Further, it is an expression, necessitating 'forcing an expression', so you need a % after msgbox. You cannot blame that on me. That is part of AutoHotkey's inconsistent, unnecessarily complicated syntax and semantics (the much touted 'ease of use'), and having to abuse message boxes to be able to see results is the result of not having a proper REPL (more 'ease of use'). AutoHotkey's documentation covers this.

Again, I want to point out, all this is already documented. Some of it (e.g. installing libraries, auto-inclusion, and forcing expressions) is part of AutoHotkey's documentation and just how AutoHotkey always works. Me re-documenting it in a tutorial will not help.
burque505 wrote:
22 Jan 2020, 09:46
IMHO a simple example is needed for each of the functions. Otherwise the barrier to entry is too high.
Skim the README. There are about 200 functions. Granted, many are very similar and that is intentional (e.g. the example for Array_All(Pred, Array) and Stream_All(Pred, Stream) should be similar). How would you include examples and not make this already long document significantly longer? How would you make it easy to spot where each function's documentation begins (currently easily visible because of the leading inline code box)? How would you depict the results since many of these constructs (e.g. function objects) have no literal syntax? How would the user running your examples see the results since AutoHotkey has no REPL (n.b. Facade performs no I/O)?

That ignores the significant effort involved. Maybe if I get enough people started they can write their own tutorials to take some of the burden off me.

Note that there are some inline examples where I believe the English description might be inadequate (e.g. in Array_Sort(Pred, Array)'s documentation to show how to sort in descending order). There is also a 'mini-tutorial' using the 8 Queens puzzle to explain an unintuitive use of Streams.
Last edited by [Shambles] on 22 Jan 2020, 14:16, edited 1 time in total.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

22 Jan 2020, 14:11

Chunjee wrote:
22 Jan 2020, 13:29
I have quicksort and Facade doesn't crawl websites.

I think this is better suited for a math heavy project like the 8 Queens problem example which sadly is over my head.
Facade's sort is stable, unlike quicksort, making it possible to sort by multiple criteria. It also contains vastly more useful functions than just its sorting routine.

Indeed, it does not crawl websites. Neither does my car. My car is still useful because it does something else that is useful. Facade is still useful despite not crawling websites because it does a lot of things that AutoHotkey should have done.

Nothing about Facade makes it only useful in math heavy projects.
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: Facade Functional Programming Suite

22 Jan 2020, 14:52

From the documentation:

Code: Select all

Dict has the following methods:

Dict.Count()
Dict.HasKey(Key)
Dict.Get(Key)
Dict.Set(Key, Value)
Dict.Delete(Key)
Dict.Clone()
Dict._NewEnum()

Get(Key) reads the value associated with a key.
However, in the Usage section the above methods appear with underscores (called functions and not methods, and I'm assuming there is an intended difference despite the frequent conflation everywhere of the terms. If you think I'm overstating this confusion, see e.g. this link), i.e.

Code: Select all

Dict_Count(Dict) returns the count of the items in Dict. It returns the cardinality if Dict represents a finite set.
Dict_HasKey(Key, Dict) returns whether Key exists in Dict. It tests set membership if Dict represents a finite set.
Please consider this code:

Code: Select all

#Include <Dict>
ChangoDict := Dict(["one", "Racing to Valhalla"], [2, "Goodbye"], ["gulp", ("four", 6)])
; msgbox % Dict.Get("one") ; Fails. 
msgbox % Dict_Get("one", ChangoDict)
; msgbox % Dict.Get(2, ChangoDict) fails
msgbox % Dict_Get("gulp", ChangoDict)
; msgbox % Dict.Count(ChangoDict) fails
msgbox % Dict_Count(ChangoDict) ; passes
msgbox % Dict_Get("gulp", ChangoDict) ; unexpected result
msgbox % ChangoDict.Get("one") ; And here is the answer
ExitApp

I hope I'm making my case re the need for examples. Otherwise, I'd make the following documentation change:

Code: Select all

Dict (replace 'Dict' in your code with the name of an exising dictionary) has the following methods:

Dict.Count()
Dict.HasKey(Key)
Dict.Get(Key)
Dict.Set(Key, Value)
Dict.Delete(Key)
Dict.Clone()
Dict._NewEnum()

Get(Key) reads the value associated with a key.


Regards,
burque505
User avatar
Chunjee
Posts: 1400
Joined: 18 Apr 2014, 19:05
Contact:

Re: Facade Functional Programming Suite

22 Jan 2020, 15:13

[Shambles] wrote:
22 Jan 2020, 13:57
It can help pay the bills if you are a Windows system administrator at a business or school. The alternative is clicking through wizards on several hundred to several thousand machines to install software or make trivial configuration changes.
This is the example I need.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

22 Jan 2020, 15:21

burque505 wrote:
22 Jan 2020, 14:52
<clip>
However, in the Usage section the above methods appear with underscores (called functions and not methods, and I'm assuming there is an intended difference despite the frequent conflation everywhere of the terms. If you think I'm overstating this confusion, see e.g. this link)
<clip>
There is no confusion.

Facade defines a class named Dict which implements the Dict type used by the functions in the Dict library. This should be wholly unsurprising to any programmer familiar with OOP programming in any programming language. Even if you don't like OOP, using OOP is the only way AutoHotkey provides to define a new type, so you will be forced to use it.

The methods are as they are to make it easier to use Dict and Object interchangeably. The "Intention" section even explains that.

The functions are as they are because functions are more useful in AutoHotkey, because AutoHotkey thoroughly hosed its OOP support. How, exactly, is a long conversation that I doubt you care about.

AutoHotkey defines how functions and methods work. You cannot blame that on me. How they work is described in AutoHotkey's documentation. Facade did not interfere with this in any way. Facade is actually quite well behaved and goes out of its way to avoid clobbering or monkey patching anything. I learned that lesson when writing Composer.

A simple overview would be:
* A function is not attached to anything. You call it like TheFunc(Arg1, Arg2). When called it operates on its arguments.
* A method is attached to a value. You call it like TheValue.TheMethod(Arg1, Arg2). When called it operates on that value, potentially with additional arguments.

AutoHotkey (n.b. AutoHotkey, not Facade, defines this behavior) looks for functions with a "_" in the name in the file with the same name as that preceeding the underscore (e.g. so Foo_Bar(X) would be looked up in the Foo.ahk file).

The reason your example fails is because you have confused function and method syntax. To call the functions, use the names as depicted in the documentation. You cannot replace "." with "_", or vice versa, and expect things to work the same. Syntax is associated with semantics, even in AutoHotkey.

You can name your variables whatever you please. If you want to name your dictionary "Dict", as Facade's own code often does (because there is usually only one dictionary being operated on at a time and it makes it clear which type is expected), feel free. Just make sure it's a local variable (you might notice Facade's code always uses force local mode, because it's the only way to avoid accidentally clobbering global variables because AutoHotkey thoroughly hosed its scope handling).

You cannot arbitrarily replace "Dict" with whatever you want wherever you want and expect it to work the same. The Dict(Items*) constructor and the various utility functions (e.g. Dict_Count(Dict)) must be called as is. Dict_Count(Foo) will work if there is a dictionary named Foo in your scope. Foo_Count(Dict) and Foo_Count(Foo) will not work because functions with those names do not exist.

Again, this is just how AutoHotkey works, which AutoHotkey documents. Me re-documenting it won't help people that don't know it. The only cure is reading the documentation that has already been written.
Last edited by [Shambles] on 22 Jan 2020, 16:14, edited 2 times in total.
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: Facade Functional Programming Suite

22 Jan 2020, 15:25

Well, that's enough for me. Thanks for your work. I wish you the best of luck with it. Over and out.
Regards,
burque505
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

22 Jan 2020, 16:03

Chunjee wrote:
22 Jan 2020, 15:13
[Shambles] wrote:
22 Jan 2020, 13:57
It can help pay the bills if you are a Windows system administrator at a business or school. The alternative is clicking through wizards on several hundred to several thousand machines to install software or make trivial configuration changes.
This is the example I need.
I doubt it very much.

A concrete example (that I can't share the code for because of obvious security reasons).

Say you want to install Deep Freeze to prevent students from perpetually infesting the lab computers with malware. You find out you cannot put this in a image because something (probably its copy protection) prevents computers using it from booting on anything but the hardware you originally installed it on.

Hmm, you could go around to every computer, run the installer by hand, key in the password by hand, and get yelled at and potentially fired by the school administration for taking several weeks. They're already looking for any excuse to eliminate your job and foist more expense on the students (hint hint: BYOD is a burden, not a boon).

Or you could poke around at the installer's GUI with WindowSpy to get the info you need to fake operating that GUI by hand (e.g. with Click), write a script to install it and key the password in for you, create a self-installer (e.g. using FileInstall), and include code to delete itself after installing. Then you could serve that file using Symantec Ghost or Active Directory.

That's a real world example from my personal life.

The 'processing' is so trivial that Facade probably wouldn't be much help. But it is a great example of a 'for work' use of AutoHotkey. I am obviously not going to show you code that includes a password, and the rest of the code would be jibberish that only makes sense for a very particular installer's GUI.

Lets look at a concrete example where Facade's processing might help.

Lets say you already have to maintain a spreadsheet of computers and the software installed on them because the school gets audited by software corporations at random. The administration expects you to fork this file over to them so they can fork it over to their lawyers, on demand.

Lets say there is certain software that either cannot be included in the image (usually because copy protection, again) or because there aren't enough licenses to put it on every computer you want to use that image on (e.g. you have 2 licences for Mathematica to go in this lab but there are 20 computers in the lab with the other software on them). You are in a similar situation when software nobody cares about the licenses to freaks out in certain situations (e.g. SMART Board drivers when there is no SMART Board connected, like on all the lab machines except the teacher's computer).

Lets say you notice that 'remembering' what goes on a computer is pretty hard when it has been reimaged ('reformatted' basically, with a set of software).

Lets say you notice that you can use Windows Management Infrastructure (WMI) to read the MAC address of each computer and you realize that will be the same even after reformatting.

Hmm, look at that, we could write scripts to bundle our own auto-installers for this extremist copy protection or limited license software, then put the files to install them in our image, then write a script to look up what MAC address we are on using WMI, then look up in a file that maps MAC addresses to names, then rejoin Active Directory with that name, then look up in the spreadsheet what software to install, then delete the whole shebang. We can run the program that does this via Active Directory or Symantec Ghost. It'll be just like installing it after reimaging by hand, only we can do it automatically, remotely, and maybe keep our job a little longer.

Now the code to do this is obviously monstrous and very specific to the software being installed (since it has to work that particular installer's GUI) and the school's administration's demands (e.g. that spreadsheet bit), but there is definitely going to be some iterating over arrays and dictionary lookups going on.

Guess what? Facade has tons of functions for that.

Hmm, and this information has to be maintained. What do you think happens when the lab computers get upgraded so the old name now has a new MAC address?

I guess we need a way to iterate over the names of each computer in each lab (hello Array_Map), since they do not change, and use DCOM (your script will need to include login credentials or be run from a Active Directory administrator account, and this requires setting up DCOM/WMI to allow this) to make the right calls to WMI (which would be the function you wrote to pass to Array_Map) to dump our new MAC->Name file that gets used to recover the custom name and software for each computer.

Slightly less monstrous, but still complex, and only useful in a particular situation.

That was another real world example from my personal life.

Hopefully the complexity of the example I just gave gives you a really good idea why it matters if AutoHotkey reports errors and is at least somewhat safe and sane.

You aren't getting any code you can change a line or two of and reuse with these examples, but they should give any Windows sysadmins some good ideas for what they can do with AutoHotkey beyond improving their score at some Cookie Clicker game.
Last edited by [Shambles] on 22 Jan 2020, 17:01, edited 3 times in total.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

22 Jan 2020, 16:33

burque505 wrote:
22 Jan 2020, 15:25
Well, that's enough for me. Thanks for your work. I wish you the best of luck with it. Over and out.
Regards,
burque505
I am sorry you were offended by my reply.

The answer I gave was honest and helpful.

I explained how functions and methods differ, how to call them, the usage of "_" in function names, and why Facade's names are as they are. This should have helped if you were stuck.

AutoHotkey itself refers to the names of methods as I did:

Code: Select all

class Foo
{
    Bar(X)
    {
        return X
    }
}

MsgBox % Foo.Bar.Name
Note the method is named "Foo.Bar". This would be so even if there were instances of this class named other things.

I will add the "Dict." prefix to the lines below the section you quoted in the name of consistency.

You would not expect a microwavable dinner to include documentation for your microwave, so why should you expect my library to include documentation for AutoHotkey? My documentation does even link to AutoHotkey's documentation where it is relevant (e.g. in the Installation section you had trouble with). You need only follow those links.

If you feel so strongly that you could improve upon the documentation, why not pitch in?
Last edited by [Shambles] on 22 Jan 2020, 17:13, edited 1 time in total.
User avatar
lvalkov
Posts: 58
Joined: 08 Mar 2019, 16:39

Re: Facade Functional Programming Suite

22 Jan 2020, 17:03

[Shambles] wrote:
20 Jan 2020, 20:06
As several asides…
  • AutoHotkey v2's new Map type is poorly named because Map is an old, standard, widely recognized name for a function that returns a sequence containing the results of applying a function to each respective element of another sequence. A port of Facade to v2 would have to use a function with the signature Map_Map(Func, Map) because Map would be the type and Map would be the function. This is why well-designed programming languages (e.g. Python) name their dictionary type something like Dict instead of the ambiguous, C++-inspired Map.
You are right on the money here. This is something that has been personally bugging me for a good while now. I am practically forced to overwrite the Map() function and resort to sticking with the class constructor only (which, by the way, does not accept any arguments, despite reporting as being variadic in nature, meaning maps require that they be populated only after their instantiation). Though certainly a far cry from the best of practices, I find this solution the least invasive, taking into account the alternatives: non-zero overhead beating of a static class with static methods into a faux-namespace; breaking naming protocols with goofy names such as fmap(), _map(), mapp(), transform()(STL brain damage).

I'd rather Map() had been renamed to UnorderedMap, HashMap, Dict or, at least, something less generic. I can't tell whether there are any plans to introduce more data structures further down the line (I hope there are) but keeping Map as Map could prove problematic.

Said workaround:

Code: Select all

UnorderedMap := Map

M := UnorderedMap.New()
M['a'] := 'A'
M['b'] := 'B'
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Facade Functional Programming Suite

22 Jan 2020, 18:01

lvalkov wrote:
22 Jan 2020, 17:03
I'd rather Map() had been renamed to UnorderedMap, HashMap, Dict or, at least, something less generic. I can't tell whether there are any plans to introduce more data structures further down the line (I hope there are) but keeping Map as Map could prove problematic.
I have attempted to keep an eye on v2 to make sure it is at least possible to port Facade to it eventually.

The most sensible way to cope that I have come up with so far is to just retain my Dict class and library but make the library work with the new Map type by changing my Dict type to use the same interface (my Get and Set methods just need to be changed to use the new meta-function).

Then you should be able to use them interchangeably unless you need to care about the order of items (which Map will not order in any reliable way except for numbers and strings) or the handling of floating-point keys. If you care about those things, you can just use Dicts and convert Maps to Dicts as necessary. Then it won't be much better or worse than v1.

I keep hoping that the developers will see the light and try to clean up all the problems with the programming language that have been pointed out to them or just switch to some popular programming language others maintain (LuaJIT or V8 would be suitable to build v2 atop, and there are good programming languages that compile to Lua and JavaScript). Facade is, in part, an attempt to cause that by showing that not only are these things real problems that are fixable, but they can even be fixed without changing the interpreter or implementing a whole new interpreter atop AutoHotkey, so surely the developers of the interpreter can fix it.

I do not have much hope any more. There are signs that they are now doing better than cloning only the bad parts of JavaScript and PHP (where AutoHotkey clearly draws a lot of inspiration). v2 now halts execution and reports unhandled errors. It has de-conflated arrays and dictionaries. It has (broken) closures. But things are still moving too fast and carelessly without learning from the past. For example, arrays can still have missing elements, and occasionally must do so, which makes them pretty useless for most array processing purposes (e.g. it hoses the semantics of reverse and sort). Introducing a dedicated null value or ensuring all built-ins have a default value you can specify would eliminate the need for this. Several operators and functions still appear to be broken (e.g. //, mod, and round).

Yes, the developers are maintaining the software for free, and for that we should be (and I am) grateful. However, v2 is going to break everyone else's code, we will have to use it to avoid being consumed by the tide of obsolescence, and I do not believe that is fair without correcting valid complaints the community has repeatedly voiced. That is pulling a Rumpelstiltskin.

Anyway, I want to do a good job with Facade for v1. There are programming languages that are more comfortable. I may move on after that as I do not expect to have a reason to write complex code in AutoHotkey for much longer. :morebeard:
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: Facade Functional Programming Suite

22 Jan 2020, 18:23

Hello, again!

As promised, I am back.

I've read the documentation as thoroughly as possible, given my intellectual boundaries.

Your work is without doubt commendable and praise worthy!

y impressions are the following:

You cannot expect a lot of feedback because the library is not easy to "take in", the documentation helps, but it's hard to comprehend as well. It's missing trivial examples of how to call its methods and functions. Some basic tutorials are imperative if you want it to become more widely adopted, and more approachable. I don't find convincing the arguments you brought against writing tutorials. You think it would be more or less futile. I beg to differ... Keep in mind that ahk is oriented towards hobbyists, not hard core programmers.

Personally I found the array functions and the dictionary ones very appealing, however the concepts of streams and sinks... Are hard to wrap my brain matter around...

In conclusion, it all felt very abstract...

To use your own words... The microwave is there, the user manual is there, but somehow they feel disconnected.... The quality of the product is high, yet the buyers are left baffling whether to push or not to push the buttons, not knowing for certain which one's which.

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

22 Jan 2020, 20:15

robodesign wrote:
22 Jan 2020, 18:23
You cannot expect a lot of feedback because the library is not easy to "take in", the documentation helps, but it's hard to comprehend as well. It's missing trivial examples of how to call its methods and functions. Some basic tutorials are imperative if you want it to become more widely adopted, and more approachable. I don't find convincing the arguments you brought against writ ing tutorials. You think it would be more or less futile. I beg to differ... Keep in mind that ahk is oriented towards hobbyists, not hard core programmers.
I appreciate this reply more than you might expect.

Yes, it is another complaint asking for more documentation, but it is not the same.

For one, I can tell you put in some effort because of specifics you mention.

If you could be more specific, I might be able to help you.

Writing replies in forums like this is something I find easy. I do not care overmuch if they are as precise and terse as possible. People also expect occasional mistakes. A lot of unnecessary verbosity is okay because few people if anyone read entire threads.

Documentation is another matter. It needs to be very well organized and concise because it is intended to both teach how to use the artifact and to be reread to jog the user's memory.

I hope this makes it clear why I am in no hurry to take on more documentation work, but I am willing to answer your questions.

On to specifics...

Facade is probably about as hard to take in as learning most of the Scheme programming language (which it strongly resembles, minus macros and closures, which I miss dearly) and a smattering of about a dozen other programming languages and libraries (the ones in the Func section of the Design document).

That you feel overwhelmed is perfectly okay and to be expected. Actually learning new concepts is hard. You aren't just learning a new syntax for C with some OOP tacked on poorly. You are actually learning something new. There was a time (up until about the mid 90s) when programmers regularly learned new concepts (Lisp was widely used commercially and it does not at all resemble C for example). Nowadays they mostly learn pointless resyntaxings of old ideas and how to glue things together.

Don't be scared by it. If you are too scared by something unfamiliar to learn about it, you will never learn anything. Start with something that seems simple and expand from there. You know AutoHotkey's operators (like +), right? Well, the Op library is mostly those operators fixed to give correct results (a surprising number of AutoHotkey's built-in operators are broken!). The next step up in complexity would probably be learning the Array and Dict libraries. List isn't hard, but is only rarely useful. I would try to learn Stream next. Finally, I would try to learn Func.

People don't start out learning about streams in Scheme either. It is considered a hard topic.

Functional programming is not the same as imperative programming. You will have to actually put in the hard effort to learn it, just like the hard effort you put in when you learned imperative programming.

Why bother? It isn't a silver bullet, but it is less error-prone because it discourages the use of mutable state and explicit control flow, and mistakes with those are among the most common sources of defects.

I am well aware that understanding cannot spring from nothing, and one of the easiest ways to learn is with analogies.

You really would be best off learning another 'proper' functional programming language by reading good tutorials on them, then return to Facade to use what you learned in AutoHotkey, but I will try to give enough of an orientation here to help you get started with Facade.

You are familiar with assignment: putting a value into a variable. We can still do that when using functional programming, but once something is assigned (e.g. by passing it as an argument or setting a variable) we try to avoid changing it. Programs rarely start in a corrupt state, but they very frequently mutate into one. The most common way they become corrupt is when you change something used multiple places and the code in those other places did not expect it to change. So how does anything ever get done in a functional programming language if nothing ever changes? We make a new, different thing, instead of changing a thing. When you do that, the other code still has the old thing and won't break because nothing changed, you just made a new thing for your own use. If you try writing imperative code with just that difference, you will slowly start to understand some of how to do functional programming.

The next stumbling block is usually getting away from using loops (as such). How can you ever write something that needs to use a loop if you can't change a loop counter or an index or something alike?

The answer in a proper functional programming language is there is this technique called tail recursion where you put the thing that would change into a function argument and then have that function call itself while computing new values, and this works okay because it isn't wasting time or (call stack) space.

AutoHotkey does not work that way, so we cannot do it that way.

That's okay though, because even in proper functional programming languages you very rarely actually write code like that. Why? Because the vast majority of loops you use come from a very limited set. Instead, you call a function that loops like you want it to and pass it a little function that tells it what you want it to do on each iteration. This tends to be somewhat shorter and a whole lot safer than when using imperative loops.

When to use each kind of loop-equivalent function?
  • You want to loop over something to compute a single value (note that that single value might still be a collection). ⇒ Use a Fold. There are Left (goes from the beginning to the end) and Right (goes from the end to the beginning) Fold varieties, and ones where you can pass an initial value and ones (1 suffixed) where the initial value is taken from the collection. One of these will almost certainly do what you want.
  • You want to loop over something to compute a sequence of new values based on the old values (like a for-each loop). ⇒ Use a Map.
  • You want to loop over something to remove certain values. ⇒ Use a Filter.
Those are, by far, used the most often.

Less often used kinds of loop-equivalent functions
  • You want to loop over something to know if something is true about every element. ⇒ Use a All.
  • You want to loop over something to know if something is true about at least one element. ⇒ Use a Exists.
  • You want to loop over something to compute cumulative results (e.g. to show the increasing totals in a shopping cart) ⇒ Use a Scan. There are varieties directly corresponding to Folds.
  • You want to loop over something to find the 'best' element(s). ⇒ Use a (Min|Max)(K)By. There are varieties for all combinations of these tasks.
  • You want to loop over several sequences where each sequence represents a separate argument ⇒ Use a ZipWith.
There are more special purpose loop-equivalent functions (e.g. Interpose and Reverse, and loops that convert sequences to dictionaries like the GroupBy* functions) and varieties that add features (e.g. ConcatZipWith concatenates the result of calling ZipWith, which is handy when the function that acts as the 'loop body' might return no results or multiple results (by returning a sequence) instead of always returning a single result), but those are used even more rarely and their usage should be clear at this point.

Now that you have this little 'language' of loop types, those reading your code can have a better idea of what your 'loop' is trying to do. They just need to read the name of the loop-equivalent function and they know what it does instead of having to try to suss it out from reading the loop body. You just write or construct (with the Func library) some code to be the loop body and it does only the minimum, custom necessary work (the loop-equivalent function does most of the work). It tends to be safer because the state manipulation is hidden inside the loop-equivalent function. It tends to be shorter because some of the logic (at least the result building) tends to be hidden inside the loop-equivalent function. And should anything be wrong with this code, it will probably be noticed because everyone is using it over and over and the defect can be fixed in one place.

If you got this far, you are probably doing at least somewhat passable functional programming. Be sure you read and understand that "Intention" section.

Old functional programming languages, like the Lisp varieties (including Scheme, which inspired most of Facade) were not interested in eradicating all side effects. The designers accepted that side effects (mutating global variables that represent 'the state of the world' in event handlers and performing I/O) were occasionally necessary, but problematic. Unnecessary uses were to be discouraged. They were not intended to be banned. This is why Dict has methods that support imperative programming just as well as it supports functional programming (and why Facade only mentions them in passing because I don't want you to use them unless you have to).

This new interest in dogmatic avoidance of all side effects is a recent development dragged into the limelight, but not yet the mainstream, by Haskell.

One important insight did come from this because languages like Haskell force the matter. There are good and bad places to put your side effects. Like the Intention section says, put them in your main procedure and event handlers, not in your processing code. Side effects make testing, debugging, and reuse a nightmare. By putting them in the right place, they won't mess up the vast majority of your code (well over 90% of it should be side effect free).

At this point you should be getting pretty good at functional programming, but some things will start to chafe.

Sometimes you really do want to do something like change a thing (and it isn't I/O or retaining 'the state of the world' in an event handler). What then? That's where Func comes in. If you have closures (as in AutoHotkey v2) you can do some of what Func does without any combinators fairly easily, but it's still more concise to use the combinators, and if someone sees the combinators they can know what is going on by recognizing the names, just like our 'loop language'. 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. Nothing I say will change that. It's like brain surgery, rocket science, and nuclear physics. It's just inherently hard. The combinators do have suggested uses, which is far more than you will usually get for help out of most of their origin language's or library's documentation.

Why bother if it is so hard? You're building functions by snapping existing functions together like Legos. Such 'Lego blocks' are likely to be reliable because they keep getting used over and over. If there is a problem, it will be noticed and can be fixed in one place. It also saves you from writing as much code because you can usually get done what you need to by just slotting a few snapped together functions into one of those loop-equivalent functions.

Hopefully it's coming together now.

So what is the deal with streams? Occasionally, you want to create data from nothing. For example, you might want to number the lines of text in a file so that people can locate specific lines. Files can obviously differ in how many lines they have, so there is no fixed array that will be long enough to hold enough numbers for every possible file. Also, having a great big array around all the time would waste a lot of space all the time. Streams solve this problem, and they have one neat feature.

You might be thinking, "I could just use an Iterator". Indeed, you could. But Iterators have one serious problem: they use mutation. If you compute line numbers, then, for whatever reason, need to go back to a line, it might get renumbered incorrectly. That particular situation is pretty easy to avoid (store the Iterator's results instead of calling it every time), but it's illustrative.

In Scheme, Streams are mostly used where you would use Iterators in a conventional programming language. Almost all popular conventional programming languages have a rich library of Iterators (Python and Ruby being good examples). AutoHotkey doesn't.

I wanted to correct this, and I thought while I was at it I should choose the best possible design, Scheme streams, instead of Iterators.

The 8 Queens example is a relatively simple example of why you might want to be able to 'remember' a location in a generated sequence. It solves a puzzle by trying to extend a guess with each possibility then filtering out combinations that are wrong. That 'extend' trick would not work if mutation was used because it is achieved by repeatedly 'resuming' from the beginning of each guess. That is also why the memoization (caching, basically) is helpful.

It is a trick you will not often need to use, but it sure is nice when you need it, and it makes things a little bit safer than they would be with Iterators because unexpected mutation can't ruin your day yet another way.

You might find it useful to imagine a stream-using function as a bunch of machines (the stream functions) connected by conveyor belts (the variables, including parameters). You can also think of functions that way, but the analogy is very direct with streams.

That should cover just about everything in a very cursory manner (stuff like the tiny String library should be clear after looking at Op, the Math library just wraps the built-in math functions with error reporting, etc.). Consider this my 'not polished enough to publish' tutorial. Ask questions about specifics if you're still stuck.

Feel free to fix it up and post it somewhere if you want.
Last edited by [Shambles] on 23 Jan 2020, 07:26, edited 4 times in total.
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: Facade Functional Programming Suite

23 Jan 2020, 04:28

Hello!

I have read your reply in entirety. It is a really good overview of the whole thing. Yes, the OP and Math libraries are easy to adopt, and I see no reasons as to why I should not .

For me, this overview manages to highlight, to unearth, why it is overall hard to switch to functional programming and more specifically, to use your library extensively. I cannot stress this enough: most people here, the AHK user base, is comprised of hobbyists, not highly advanced programmers. I, personally, never coded with OOP in mind. I do not earn my living coding, i do it for fun/pleasure/mental exercise. I am not sure if this analogy is appropiate, but asking AHK users to adopt functional programming is like trying to put a reactor on a wheelcart and expecting it will all go nicely ;-). To adopt this model of programming, using Lego-like functions, and avoid mutations, requires a different mindset that most AHK users do not have. I dare say, only people like you and a few others from this forum, are actual programmers. Knowing just AHK makes you half-programmer. Personally, i believe I code rubbish and messy because I do not stay for hours/days to create complete plans of what my project is going to be like [user interface, features, how to organize the code and other details]. I do not do project / technical specifications. I just whip-it-up on the go, as an artist painting a damsel in utter distress... However , I do not shy away from doing seemingly complex and complete projects. My intent is to become an actual programmer in a different language, an actual programming language. I doubt AHK v2 will turn into something one can call a proper programming language. Recently, i got my mittens into Rust.

Anyways, good luck with your stuff. And do not worry, it is a niche thing you do... it is fine to have only a few people using Façade, especially given the AHK user base. I intend to adopt OP and Math libraries.

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

23 Jan 2020, 06:06

robodesign wrote:
23 Jan 2020, 04:28
For me, this overview manages to highlight, to unearth, why it is overall hard to switch to functional programming and more specifically, to use your library extensively. I cannot stress this enough: most people here, the AHK user base, is comprised of hobbyists, not highly advanced programmers. I, personally, never coded with OOP in mind. I do not earn my living coding, i do it for fun/pleasure/mental exercise. I am not sure if this analogy is appropiate, but asking AHK users to adopt functional programming is like trying to put a reactor on a wheelcart and expecting it will all go nicely ;-). To adopt this model of programming, using Lego-like functions, and avoid mutations, requires a different mindset that most AHK users do not have. I dare say, only people like you and a few others from this forum, are actual programmers. Knowing just AHK makes you half-programmer. Personally, i believe I code rubbish and messy because I do not stay for hours/days to create complete plans of what my project is going to be like [user interface, features, how to organize the code and other details]. I do not do project / technical specifications. I just whip-it-up on the go, as an artist painting a damsel in utter distress... However , I do not shy away from doing seemingly complex and complete projects. My intent is to become an actual programmer in a different language, an actual programming language. I doubt AHK v2 will turn into something one can call a proper programming language. Recently, i got my mittens into Rust.

Anyways, good luck with your stuff. And do not worry, it is a niche thing you do... it is fine to have only a few people using Façade, especially given the AHK user base. I intend to adopt OP and Math libraries.
It may be that the skill level in the AutoHotkey community is low.

Frankly, I am not buying that. I happen to know that several regulars have a very good command of the Windows API, much better than me, and much better than most professional programmers. One can reasonably assume this is not the only programming knowledge they have acquired (though some of them seem to know very little about programming language design). These might be an extreme minority, but I am far from the only competent programmer here.

Were it true, it would still not be desirable to keep the community a low-skill ghetto. Being a beginner is nothing to be ashamed of. Being unwilling to learn and improve is another matter. And yes, there are people who are interested in learning only other things than programming, but few if any of those people also write programs in AutoHotkey. The people reading these forums self-select, and they are selecting themselves to be programmers, whether they are willing to own up to it or not.

Low-skill programmers do violence to our technological infrastructure. There is a good reason we don't let unschooled children loose with a sledgehammer to do brain surgery.

Hopefully Facade helps improve the skill level here by making it possible to adopt better practices in AutoHotkey and by pushing AutoHotkey's design in a better direction.

As for doing specifications for everything, you might benefit from reading Facade's Lessons_Learned.txt. In practice, almost nobody engages in 'big design up front'. Competent programmers will think about how to solve a problem first (they do not code before thinking!), then try one or more ideas, then realize they forgot to consider some things and/or their ideas were bad, revise, and repeat. Those 'pretty designs' are the aftermath of this iterative process, though few are willing to admit this is how the sausage gets made.

Facade probably went through about 3 near complete redesigns and rewrites before it arrived in its current state, and a long series of more minor changes. This is the most redesigning and rewriting I have ever had to do, and I have been quite embarrassed by it. It might seem like all I had to do was clone most of Scheme and some parts of a bunch of other programming languages, but figuring out that's what I should be doing took a lot of effort, and much of what you see here is convergent evolution, not planning. I tried to give credit where it is due and help people that already know similar languages by crediting the first to 'discover' a construct, but that does not mean that I started out by knowingly copying from them (e.g. the recently removed CWhile was entirely 'my own invention', and I only recognized it was an exact match for a construct from Joy after the last redesign of it).

AutoHotkey teaches bad habits. Please learn something better as a first programming language. I would suggest Python (the thing beginners complain the most about, being forced to indent properly, is one of the best reasons to have them use it). Once you know what parts of AutoHotkey to ignore (e.g. goto, gosub, 'variable substitution' where possible, command substitution in v2 where possible, the use of 'magic variables' like A_Index where possible, any scope except force local, etc.), you can use it safely and without making too much of a mess.

I am not okay with almost no one but myself using Facade. I do not enjoy working on it. I made it because I needed it. I made it because I suspect there are others out there that do the kind of work I have done. And I made it to try to push AutoHotkey's development into a better direction so that I and others like me would suffer less from it. The time is approaching when I will no longer need it, so if nobody else benefits from it and everyone else ignores its ideas, this has been pointless.

I may have to accept that outcome, but I will not like it, and I will do what I can to prevent it.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 109 guests