简易链式调用@thread_as

在clojure里有几个流水线宏->,->>,他们是为了避免出现过多中间变量而设计的,
例子:

(->> coll
        (filter #(> % 1))
        (map inc))

这两个宏默认的参数位置分别是函数的第一个位置和最后一个位置
为了简单起见,我写了一个thread-as宏,以后还得接着改良

# 替换表达式里的临时变量
function Base.replace(expr::Expr,prev::Symbol,into)
    for index = 1:length(expr.args)
        if expr.args[index] == prev
            expr.args[index] = into
        end
    end

end
macro thread_as(expr,as,proccesses...)
    val = eval(expr)
    for proccess in proccesses
        replace(proccess,as,val)
        val = eval(proccess)
    end
    val

end

试一试

@thread_as([1 2 3 4],filter(x->x>1,_),map(x->x+1,_)) # -> [3 4 5]
# 也请各位小伙伴试一试看,我也不一定改

另外有些特殊符号不能用,比如$,我也不知道怎么回事

总结以下从这个宏的编写学到的东西:宏就是把表达式看作数据,并对其进行操作,使其生成新的表达式的过程

1 个赞

(我觉得这个叫“链式调用(chaining)”好一点,串行对应的是并行,有别的含义了。

有一些现有的包能做到这一点,不过我觉得标准库里的那些看起来的纯函数就应该支持返回函数。

julia> import Base: filter

julia> filter(f::Function)::Function = x -> filter(f, x)
filter (generic function with 9 methods)

julia> [1 2 3 4] |> filter(x -> x>1) |> x -> x.+1
3-element Array{Int64,1}:
 3
 4
 5

函数链式调用的讨论 issue。这里面神仙打架

julia> Base.getindex(f::Function, x...) = (y...) -> f(x..., y...)

julia> [1 2 3 4] |> filter[x -> x>1] |> map[x -> x.+1]
3-element Array{Int64,1}:
 3
 4
 5

—— @MikeInnes


部分现有的包

Lazy.jl

using Lazy

# isprime defined in terms of the prime numbers:
isprime(n) =
  @>> primes begin
    takewhile(x -> x<=sqrt(n))
    map(x -> n % x == 0)
    any; !
  end

Pipe.jl

@pipe a |> b(x,_)    # == b(x,a) #Not: (b(x,_))(a) 

@pipe a |> b(_...)   # == b(a...)
@pipe a |> b(_(1,2)) # == b(a(1,2))
@pipe a |> b(_[3])   # == b(a[3])

Hose.jl

@hose a |> b(x, _) # produces b(x, a)
@hose a |> _[b] # produces a[b]
@hose a |> @testmacro _ b # equivalent of @testmacro(a, b)
2 个赞

2020.4.12 改进

考虑到一些惰性操作,思路改为将表达式翻译完毕后再返回

macro thread_as(nums_expr,as,exprs...)

    fn(from,as,to) = Expr(:call,replace(to.args,as=>from)...)

    iter = function iter(exprs,res)
        if length(exprs) == 1
            fn(res,as,first(exprs))
        else
            iter(Iterators.drop(exprs,1),fn(res,as,first(exprs)))
        end
    end

    iter(exprs,nums_expr)
end