I see your point. However, my gut is telling me that your solution still 
conflates two separate issues. The first is, What's a good way to mutate an 
array element by element with a function that takes a scalar input? The 
second is, how do I "pipe" (is this still the right word?) the result of 
one such mutation as an argument to another such mutation? I think I would 
prefer two convenient, easily composable syntaxes to a single syntax that 
did both. For instance, I can see easily confusing myself by expecting

foreach(A, step1!, step2!, step3!)

to act like

for a in A
    a = step3!(step2!(step1!(a)))
end

at least given the name "foreach". Of course, it goes without saying that 
you ought to use whatever you find most helpful.

On Wednesday, June 10, 2015 at 10:48:27 AM UTC-4, Tom Breloff wrote:
>
> I agree... using the pipe operator for this would be confusing at best, 
> and breaking at worst.  However it would still be cool to be able to 
> connect multiple functions in one pass.  What about:
>
>
> julia> function foreach(A::AbstractArray, f::Function, fs::Function...)
>            for x in A
>                f(x)
>            end
>            for g in fs
>                foreach(A, g)
>            end
>            A
>        end
> foreach (generic function with 1 method)
>
> julia> type MyType; x::Int; end
>
> julia> A = map(MyType, 1:2)
> 2-element Array{MyType,1}:
>  MyType(1)
>  MyType(2)
>
> julia> add_one!(mt::MyType) = mt.x += 1
> add_one! (generic function with 1 method)
>
> julia> add_two!(mt::MyType) = mt.x += 2
> add_two! (generic function with 1 method)
>
> julia> foreach(A, add_one!)
> 2-element Array{MyType,1}:
>  MyType(2)
>  MyType(3)
>
> julia> foreach(A, add_two!)
> 2-element Array{MyType,1}:
>  MyType(4)
>  MyType(5)
>
> julia> foreach(A, add_two!, add_one!, add_one!)
> 2-element Array{MyType,1}:
>  MyType(8)
>  MyType(9)
>
>
> One note... this is different than applying "f(g(h(x)))" for each item 
> independently.  In that case there may be simpler answers.  My use case is 
> when the items depend on the state of others, and so the first operation 
> needs to be applied to all items before starting the next operation.  In 
> effect, I want to replace this:
>
> for x in A; step1!(x); end
> for x in A; step2!(x); end
> for x in A; step3!(x); end
>
> with this:
>
> foreach(A, step1!, step2!, step3!)
>
>
>
>
>
> On Wednesday, June 10, 2015 at 10:06:39 AM UTC-4, David Gold wrote:
>>
>> Pipe and map seem like related but orthogonal concepts; I don't know if 
>> they ought to be given the same operator. But I may just be looking at 
>> things wrongly.
>>
>> I'd sooner see a tricked-out array comprehension syntax. Something like
>>
>> ![ add_one(x) for x in A ]
>>
>> If the target array were ambiguous, one could write
>>
>> !A[ f(add_one(x), add_two(y)) for x in A, y in B]
>>
>> which could play well with some shorthand for taking a comprehension over 
>> the entirety of an array, e.g.
>>
>> ![ add_one(.A) ]
>>
>> or
>>
>> !A[ f(add_one(A[.i]), add_two(B[.i])) ]
>>
>>
>> On Tuesday, June 9, 2015 at 8:37:51 PM UTC-4, Tom Breloff wrote:
>>>
>>> Stefan: Yes that's obviously valid.  Simon's "foreach" is essentially 
>>> what I mean.  
>>>
>>> Although overriding the pipe operator would probably break things, I 
>>> think ideally there would be a built-in solution that looks similar to this:
>>>
>>>
>>> julia> |>(A::AbstractArray, f::Function) = (for x in A; f(x); end; A)
>>> |> (generic function with 7 methods)
>>>
>>> julia> type MyType; x::Int; end
>>>
>>> julia> add_one!(mt::MyType) = mt.x += 1
>>> add_one! (generic function with 1 method)
>>>
>>> julia> A = map(MyType, 1:2)
>>> 2-element Array{MyType,1}:
>>>  MyType(1)
>>>  MyType(2)
>>>
>>> julia> A |> add_one! |> add_one!
>>> 2-element Array{MyType,1}:
>>>  MyType(3)
>>>  MyType(4)
>>>
>>>
>>>
>>>

Reply via email to