Home > database >  Is there a way to pass something more advanced like a method or a comparison to a function?
Is there a way to pass something more advanced like a method or a comparison to a function?

Time:10-19

So I was trying to remake some Array.prototype functions from Javascript in Applescript. While trying to do that I noticed, that many Javascript functions use something that I think is called an arrow function.

Here is a little recap from what I understand of it:

Arrow functions are built up like this (shown by the Array.prototype.filter()-method):

words.filter(word => word.length > 6);
 ^^^    ^^^  ^^^  ^^      ^^^
  1      2    3   4        5

Example taken from mozilla.org.

  1. This specifies the array/list targeted. Easy to implement in Applescript.
  2. This specifies the built-in function used. I have no idea how to get this to work because I do not know how to implement steps 3, 4 and 5.
  3. This assigns the value that is "assigned" to each item in the list. This could be done statically with something like repeat with word in words ... (except for the fact that those words are reserved.), but I do not know of a way to do this dynamically.
  4. This is the sign that "points" the compiler to tell it what should happen. I do not think that this is necessary to implement.
  5. This is (in this case) a comparison, whether a given word has a higher character count of 6. This decides if the item should stay in or not. This could be recreated using if count of characters of word > 6 then set end of someNewListWeCreatedOutsideThisLoop to word.

These arrow functions can also, instead of comparisons, have functions instead like forEach():

array1.forEach(element => console.log(element));

Example taken from mozilla.org.

Here is what I've tried:

on myFunc(fn)
  fn
end
myFunc(log "Hello World")

This logs "Hello World" and afterwards throws an error about how not enough parameters were passed.

Here is a bit of a hacky workaround using the command line:

set theWords to {"These", "are", "Words."}

forEach(theWords, "theWord => log theWord")

on forEach(theArray, arrowFunction)
    set AppleScript's text item delimiters to " => "
    set arrowFunction to text items of arrowFunction
    set AppleScript's text item delimiters to " "
    return (do shell script "osascript -e 'repeat with " & item 1 of arrowFunction & " in (every word of \"" & (theArray as string) & "\")' -e '" & item 2 of arrowFunction & "' -e 'end repeat'")
end forEach

This method is supposed to work, and even if it would, it would have a tiring syntax, performance speed would be slow and I am almost sure that I have overlooked some stylish Applescript method.

CodePudding user response:

Wrap a handler containing your custom behavior in a script object. You can then pass the script object as a parameter to another handler and call it there.

script Foo
    to doStuff(a, b)
        return a   b
    end doStuff
end script

to bar(obj)
   obj’s doStuff(1, 2)
end bar

bar(Foo) 
--> 3

CodePudding user response:

Calling function from function in the AppleScript is possible, so following is closer to prototype of JavaScript. Not that you can assign to first function some better name than "prototype". For example, "wordsFilteringFunctions" to indicate that this prototype is designed for word filtering tasks.

UPDATE: If I understand correctly at least now, you want to control the behaviour of your prototype function based on some parameter. For example, based on the applied comparison sign like here:

set aList to words of "So I was trying to remake some Array.prototype functions from Javascript in Applescript. While trying to do that I noticed, that many Javascript functions use something that I think is called an arrow function."
prototype(aList, "<", 6)

on prototype(aList, operation, N)
    if operation is ">" then
        filterWithGreaterThan(aList, N)
    else
        filterWithLessThan(aList, N)
    end if
end prototype


on filterWithLessThan(aList, N)
    set filteredList to {}
    repeat with anItem in aList
        if length of anItem < 6 then set end of filteredList to contents of anItem
    end repeat
    return filteredList
end filterWithLessThan


on filterWithGreaterThan(aList, N)
    set filteredList to {}
    repeat with anItem in aList
        if length of anItem > 6 then set end of filteredList to contents of anItem
    end repeat
    return filteredList
end filterWithGreaterThan
  • Related