Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass indexes to ARRAY/INITIAL function. #2193

Closed
Siskin-Bot opened this issue Feb 15, 2020 · 0 comments
Closed

Pass indexes to ARRAY/INITIAL function. #2193

Siskin-Bot opened this issue Feb 15, 2020 · 0 comments
Labels

Comments

@Siskin-Bot
Copy link
Collaborator

Submitted by: rebolek

ARRAY/INITIAL accepts a function. I think that it should pass index to that function so the function would be much more useful.

Old code:

>> array/initial length: 10 func [] [-- length]
== [10 9 8 7 6 5 4 3 2 1]

New code:

>> array/initial 10 func [i] [i]
== [1 2 3 4 5 6 7 8 9 10]

Imported from: CureCode [ Version: r3 master Type: Wish Platform: All Category: Mezzanine Reproduce: Always Fixed-in:none ]
Imported from: metaeducation#2193

Comments:

Rebolbot commented on Feb 18, 2015:

Submitted by: fork

I've been experimenting with the idea that when functions are used in circumstances like this, that the parameter be via refinement... and whether the parameter is passed depends on if the refinement is in the spec.

The thing is that there might be a "stateful" function that already knows how many times it has been called, and forcing a parameter could complicate it to needing to write an adapter. So my idea is more like allow both:

>> array/initial length: 10 func [] [-- length]
== [10 9 8 7 6 5 4 3 2 1]
>> array/initial 10 func [/index i] [i]
== [1 2 3 4 5 6 7 7 9 10]

"Sniffing" for the capability to take a refinement is not something that is made particularly easy today, but as with many things, it could be made easier.

This is all ignoring the name "ARRAY" which is a separate question. :-)


Rebolbot commented on Feb 22, 2015:

Submitted by: BrianH

ARRAY can generate multidimensional blocks, so the index passed should be either a direct index for single dimensions or a block of indexes for multiple dimensions; or, for usability, pass in the same number of parameters as there are dimensions using a composed argument to APPLY.

We will probably need to use APPLY anyway, since the current model isn't very op!-friendly, and we want the actual arity and evaluation model of the function's arguments to be ignored so our code is more robust. It gets trickier when you consider that the multi-dimensional arrays are composed with recursive calls to ARRAY, which would probably require some kind of intermediate function to be passed which curries parameters if we continue to do it this way. We should see if there's an efficient way to do this.

Still, this seems like a good idea. The way we handled this usage model was to have the passed function do a counter as a side effect. Something that works with pure functions would be preferable.

(The above was completely ignoring Fork's refinement suggestion, since APPLY can handle optional arguments without needing a refinement in the function.)


Rebolbot commented on Feb 23, 2015:

Submitted by: BrianH

OK, I figured out a reasonably efficient implementation of this. It passes the indexes of the current element to the value function in the order specified with the size block, but calls that function with APPLY so the function doesn't necessarily have to take those index arguments, since APPLY ignores evaluation modes and arity, padding missing arguments with nones. It uses an internal function option for the recursive calls, but it enforces internal use of that option by using a bound tag word argument.

array: func [
    "Makes and initializes a series of a given size."
    size [integer! block!] "Size or block of sizes for each dimension"
    /initial "Specify an initial value for all elements"
    value {Initial value (will be called each time if a function)}
    /local block rest word
    /with tag indexes
] [
    unless same? :tag 'tag [with: tag: indexes: none]   ; Enforced internal
    if block? size [
        if all [not with any-function? :value] [
            indexes: append/dup make block! 2 * length? size [index? block] length? size
        ]
        if tail? rest: next size [rest: none]
        unless integer? set/any 'size first size [
            cause-error 'script 'expect-arg reduce ['array 'size type? :size]
        ]
    ]
    block: make block! size
    case [
        block? :rest [
            either any-function? :value [
                word: in make object! copy [x: block] 'x
                indexes: change next indexes word
                loop size [
                    set word insert/only get word array/initial/with rest :value 'tag indexes
                ]
                block: get word
            ] [
                loop size [block: insert/only block array/initial rest :value]
            ]
        ]
        series? :value [
            loop size [block: insert/only block copy/deep value]
        ]
        any-function? :value [
            unless indexes [indexes: [index? block]]
            loop size [block: insert/only block apply :value head indexes]
        ]
        insert/dup block value size
    ]
    head block
]

Here's an example of its use:

>> array/initial [3 4] func [x y] [ajoin [x " " y]]
== [["1 1" "1 2" "1 3" "1 4"] ["2 1" "2 2" "2 3" "2 4"] ["3 1" "3 2" "3 3" "3 4"]]
>> array/initial [3 4] does [random 100]
== [[30 79 47 79] [37 52 45 74] [23 36 60 86]]

Rebolbot commented on Mar 2, 2015:

Submitted by: BrianH

PR: rebol/rebol#235


Ladislav mentioned this issue on Feb 11, 2016:
APPLY should raise an error on excess arguments


Rebolbot added the Type.wish on Jan 12, 2016


Oldes added a commit to Oldes/Rebol3 that referenced this issue on Nov 29, 2018:
FEAT: Pass indexes to ARRAY/initial function


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants