# Finding the number of arguments of an anonymous function

**URL:** <https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394>\
**Category:** General Usage\
**Created:** [May 20, 2019, 9:35am UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394 "2019-05-20T09:35:30Z")\
**Posts on this page:** 12\
**Page:** 2

<div class="post-metadata">

**Author:** ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)\
**Post date:** [May 20, 2019, 2:31pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/21 "2019-05-20T14:31:27Z")

</div>

Because I want to allow both options, a single-argument form for `onsitefield` (with one behaviour) and a two-argument form (with a different behaviour).

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 20, 2019, 2:42pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/22 "2019-05-20T14:42:33Z")

</div>

Wouldn’t the multi-argument one not be an onsite field but an interaction field though? You could just have another kwarg called `interaction_field` that takes a two arg function.

---

<div class="post-metadata">

**Author:** ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)\
**Post date:** [May 20, 2019, 2:48pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/23 "2019-05-20T14:48:54Z")

</div>

To me they are conceptually the same. They are a modification of the onsite energy: the single-parameter form _replaces_ the value of the onsite energy, while the two-argument form transforms the existing onsite energy in some site-dependent way (I’m here using the language of a tight-binding electron lattice). So yes, I could split the API into two different kwargs with different names, but I would do that as a result of my limitations to instrospect method arguments, not because I would prefer to do so (it becomes less convenient).

This is why I preferred to pose the question more as “can Julia do this?”. And “can it do it fast?”. It seems `Base.@pure` is the answer, but it is dangerous. I wonder whether having a standard, fast and safe way to do this in Base would be desirable (i.e. Github-issue-worthy).

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 20, 2019, 3:02pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/24 "2019-05-20T15:02:23Z")

</div>

Ohh, I see. I thought when you were talking about a two argument function that would be some coupling between sites `i` and `j`, but it seems you mean its an onsite field with a parameter `o` and _possibly_ a site dependence `i`?

If I’m understanding correctly and `o` is a constant across the lattice, shouldn’t it just be passed as a constant to `hamiltonian!`? ie, you have in one case

```julia
hamiltonian!(h; onsitefield = o)

```

where now you just do `h += o*I` and in the other case

```julia
hamiltonian!(h; onsitefield = i -> cos(i) * o)

```

and this time you have to `h[i, i] += cos(i)*o`? Or am I still missing something?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 20, 2019, 3:13pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/25 "2019-05-20T15:13:16Z")

</div>

By the way (this is a bit off topic), since it seems you’re doing an exact diagonalization by looping over the indices, I found a much more performant way to build up lattice Hamiltonians so long as they’re sparse. Here’s an example with the transverse field Ising model (TFIM)

```julia
using LinearAlgebra, Arpack, SparseArrays

⊗(A, B) = kron(A, B)

function exact_solve_TFIM(g, L)
    id = [1.0 0.0; 0.0 1.0] |> complex
    σˣ = [0.0 1.0; 1.0 0.0] |> complex
    σᶻ = [1.0 0.0; 0.0 -1.0] |> complex
    σz(i) = foldl(⊗, sparse.([i==j ? σᶻ : id for j in 1:L]))
    σx(i) = foldl(⊗, sparse.([i==j ? σˣ : id for j in 1:L]))
    σzσz(i) = σz(i)*σz(i+1)
    H = -sum(σzσz, 1:(L-1)) - g * sum(σx, 1:L)
    (λ, ϕ) = eigs(H, nev=1, which=:SR)
    return ϕ, λ, H
end

```

not sure if that’s helpful at all.

---

<div class="post-metadata">

**Author:** ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)\
**Post date:** [May 20, 2019, 3:13pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/26 "2019-05-20T15:13:48Z")

</div>

@Mason,

the above is of course a simplified version of the real problem, but I didn’t want to distract with non-essential details. But given your kind interest, here is goes.

The most relevant application of this would be wanting to apply a magnetic field or a strain field to a tight-binding hamiltonian. What is modified in this situation is not the diagonal (onsite energies `h[i,i]`), but the hoppings between neighboring sites (`h[i,j]` for linked `i,j`). The magnetic field _multiplies_ the existing hopping by a Peierls phase (`h[i,j] * exp(im * dot(A(r(i), r(j)), r(i)-r(j)))`), for some vectors `A(r)` and `r(i)`. The strain field does a similar thing, multiplying the hoppings by a real factor. This would be achieved with `hoppingfield = (i,j,h) -> h*...`.

However I also want to be able to _replace_ all hoppings by something else using the same API, not just multiply them. This can be done with the above, three-argument form, of course, but I wanted to explore whether I could use a two-argument form of `hoppingfield` to dispatch to a faster replace-only method. Such a use case would have the user write `hoppingfield = (i,j) -> ...`, and the code could detect this different usage, and dispatch accordingly.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [May 20, 2019, 3:13pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/27 "2019-05-20T15:13:53Z")

</div>

`methods()` is going to have world age problems with `@pure`. Especially if you are talking about a package where users can define new methods at any time. (I’m not saying actually I understand `@pure`, but doing things like this have turned out badly for me)

I think you want to pass in a struct. It just works better with multiple dispatch than passing a function. Use a macro if you have to reduce boilerplate.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 20, 2019, 3:23pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/28 "2019-05-20T15:23:53Z")

</div>

Ah of course. Sorry for dragging this away from your original question. Could you maybe just have a separate kwarg for the Peierls phase? Not the most elegant solution I know.

It really is too bad that we don’t have a way to turn off some of the genericness of Julia functions. Having objects with a definite type signature / number of args could be useful in many circumstances.

---

<div class="post-metadata">

**Author:** ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)\
**Post date:** [May 20, 2019, 3:28pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/29 "2019-05-20T15:28:49Z")

</div>

FWIW, `applicable` seems to fare fairly well and should be safe:

```julia
julia> a(f) = applicable(f, 1) ? f(1) : f(1,2);

julia> t(f) = try; f(1); catch; f(1,2); end;

julia> m(f) = first(methods(h)).nargs == 1 ? f(1) : f(1,2);

julia> @btime a($h)
  156.568 ns (0 allocations: 0 bytes)
3

julia> @btime t($h)
  6.479 μs (2 allocations: 48 bytes)
3

julia> @btime m($h)
  3.611 μs (14 allocations: 784 bytes)
3

```

---

<div class="post-metadata">

**Author:** ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)\
**Post date:** [May 20, 2019, 4:06pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/30 "2019-05-20T16:06:25Z")

</div>

> [@pfitzseb](#):
>
> FWIW, `applicable` seems to fare fairly well and should be safe:

This is precisely what I was looking for! Many thanks @pfitzseb

---

<div class="post-metadata">

**Author:** ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)\
**Post date:** [May 20, 2019, 4:11pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/31 "2019-05-20T16:11:37Z")

</div>

> [@Mason](#):
>
> By the way (this is a bit off topic), since it seems you’re doing an exact diagonalization by looping over the indices, I found a much more performant way to build up lattice Hamiltonians so long as they’re sparse. Here’s an example with the transverse field Ising model (TFIM)

Thanks for that @Mason. I actually build my sparse d-dimensional lattice Hamiltonians in a rather general way, see [GitHub - pablosanjose/Elsa.jl: Efficient lattice simulation algorithms - a Julia library](https://github.com/pablosanjose/Elsa.jl) for details if you’re interested. What I describe above is about efficiently modifying a Hamiltonian in-place once it’s created.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [May 20, 2019, 4:14pm UTC](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394/32 "2019-05-20T16:14:51Z")

</div>

You could do

```julia
function hamiltonian!(h; onsitefield = nothing, onsitefield_nonautonomous = nothing)
if onsitefield !== nothing && onsitefield_nonautonomous !== nothing
error("at most one of onsitefield or onsitefield_nonautonomous is supported")
elseif onsitefield === nothing && onsitefield_nonautonomous === nothing
onsitefield = (o,i) -> o
elseif onsitefield === nothing && onsitefield_nonautonomous !== nothing
onsitefield = onsitefield_nonautonomous
else 
onsitefield = (o, i)-> onsitefield(o)
end
#function body
end

```

[Previous page](https://discourse.julialang.org/t/finding-the-number-of-arguments-of-an-anonymous-function/24394.md?page=1)
