サーチ…


構文

  • f(n)= ...
  • 関数f(n)... end
  • n ::タイプ
  • x - > ...
  • f(n)do ... end

備考

最も一般的な汎用関数の他に、組み込み関数もあります。そのような関数にはisisatypeofthrowおよび同様の関数が含まれます。組み込み関数は、通常、JuliaではなくC言語で実装されるため、ディスパッチの引数型に特化することはできません。

数字を四角にする

これは、関数を定義する最も簡単な構文です:

square(n) = n * n

関数を呼び出すには、丸括弧(間にスペースを入れないでください)を使用します。

julia> square(10)
100

関数はJuliaのオブジェクトであり、他のオブジェクトと同様にREPLに表示することができます。

julia> square
square (generic function with 1 method)

すべてのジュリア関数は、デフォルトで汎用(別名多形とも呼ばれます)です。私たちのsquare関数は、浮動小数点値と同様に機能します:

julia> square(2.5)
6.25

...または行列さえ:

julia> square([2 4
               2 1])
2×2 Array{Int64,2}:
 12  12
  6   9

再帰関数

単純再帰

再帰と三項条件付き演算子を使用して、組み込みfactorial関数の代替実装を作成することができます。

myfactorial(n) = n == 0 ? 1 : n * myfactorial(n - 1)

使用法:

julia> myfactorial(10)
3628800

木を使った作業

再帰関数は、多くの場合、データ構造、特にツリーデータ構造に最も役立ちます。 Juliaのは木構造であるため、再プログラミングはメタプログラミングにとって非常に便利です。たとえば、以下の関数は、式で使用されるすべてのヘッドの集合を集めます。

heads(ex::Expr) = reduce(∪, Set((ex.head,)), (heads(a) for a in ex.args))
heads(::Any) = Set{Symbol}()

私たちの機能が意図したとおりに機能していることを確認できます:

julia> heads(:(7 + 4x > 1 > A[0]))
Set(Symbol[:comparison,:ref,:call])

この関数はコンパクトで、 高次関数reduce 、データ型のSet 、ジェネレータ式など、さまざまな高度な手法を使用しています。

派遣入門

::構文を使用して、引数のをディスパッチできます。

describe(n::Integer) = "integer $n"
describe(n::AbstractFloat) = "floating point $n"

使用法:

julia> describe(10)
"integer 10"

julia> describe(1.0)
"floating point 1.0"

通常、静的複数ディスパッチまたは動的単一ディスパッチのいずれかを提供する多くの言語とは異なり、ジュリアは完全な動的複数ディスパッチ機能を備えています。つまり、複数の引数に対して関数を特殊化することができます。これは、特定の型の操作のための特別なメソッドと他の型の代替メソッドを定義するときに便利です。

describe(n::Integer, m::Integer) = "integers n=$n and m=$m"
describe(n, m::Integer) = "only m=$m is an integer"
describe(n::Integer, m) = "only n=$n is an integer"

使用法:

julia> describe(10, 'x')
"only n=10 is an integer"

julia> describe('x', 10)
"only m=10 is an integer"

julia> describe(10, 10)
"integers n=10 and m=10"

オプションの引数

Juliaは、関数がオプションの引数を取ることを可能にします。その背後には、マルチディスパッチの特別なケースとして実装されています。たとえば、一般的なFizzバズ問題を解いてみましょう。デフォルトでは1:10の範囲の数値に対して行いますが、必要に応じて異なる値を設定します。また、 FizzBuzzさまざまなフレーズを使用できます。

function fizzbuzz(xs=1:10, fizz="Fizz", buzz="Buzz")
    for i in xs
        if i % 15 == 0
            println(fizz, buzz)
        elseif i % 3 == 0
            println(fizz)
        elseif i % 5 == 0
            println(buzz)
        else
            println(i)
        end
    end
end

REPLでfizzbuzzを調べると、4つの方法があると言われています。許可される引数の組み合わせごとに1つのメソッドが作成されました。

julia> fizzbuzz
fizzbuzz (generic function with 4 methods)

julia> methods(fizzbuzz)
# 4 methods for generic function "fizzbuzz":
fizzbuzz() at REPL[96]:2
fizzbuzz(xs) at REPL[96]:2
fizzbuzz(xs, fizz) at REPL[96]:2
fizzbuzz(xs, fizz, buzz) at REPL[96]:2

パラメータが指定されていないときにデフォルト値が使用されていることを確認できます。

julia> fizzbuzz()
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz

オプションのパラメータは、提供する場合に受け入れられ、尊重されます。

julia> fizzbuzz(5:8, "fuzz", "bizz")
bizz
fuzz
7
8

パラメトリックディスパッチ

Vector{T}Dict{K,V}などのパラメトリック型で関数を送出する必要があることがよくありますが、型パラメータは固定されていません。この場合は、パラメトリックディスパッチを使用して処理できます。

julia> foo{T<:Number}(xs::Vector{T}) = @show xs .+ 1
foo (generic function with 1 method)

julia> foo(xs::Vector) = @show xs
foo (generic function with 2 methods)

julia> foo([1, 2, 3])
xs .+ 1 = [2,3,4]
3-element Array{Int64,1}:
 2
 3
 4

julia> foo([1.0, 2.0, 3.0])
xs .+ 1 = [2.0,3.0,4.0]
3-element Array{Float64,1}:
 2.0
 3.0
 4.0

julia> foo(["x", "y", "z"])
xs = String["x","y","z"]
3-element Array{String,1}:
 "x"
 "y"
 "z"

単純にxs::Vector{Number}書こうとするかもしれません。しかし、これは、型が明示的にVector{Number}オブジェクトに対してのみ機能します。

julia> isa(Number[1, 2], Vector{Number})
true

julia> isa(Int[1, 2], Vector{Number})
false

これが原因であるパラメトリック不変物体Int[1, 2] はない Vector{Number}それだけ含めることができるので、 Int一方、SをVector{Number}数字の任意の種類を含有することができると予想されます。

汎用コードの記述

ディスパッチは非常に強力な機能ですが、タイプごとにコードを特化するのではなく、すべてのタイプで機能する汎用コードを記述する方がよい場合がよくあります。ジェネリックコードを書くことは、コードの重複を避ける。

たとえば、整数のベクトルの平方和を計算するコードを次に示します。

function sumsq(v::Vector{Int})
    s = 0
    for x in v
        s += x ^ 2
    end
    s
end

しかし、このコードはIntのベクトルに対してのみ機能します。 UnitRangeでは動作しません:

julia> sumsq(1:10)
ERROR: MethodError: no method matching sumsq(::UnitRange{Int64})
Closest candidates are:
  sumsq(::Array{Int64,1}) at REPL[8]:2

Vector{Float64}では動作しません:

julia> sumsq([1.0, 2.0])
ERROR: MethodError: no method matching sumsq(::Array{Float64,1})
Closest candidates are:
  sumsq(::Array{Int64,1}) at REPL[8]:2

このsumsq関数を書く良い方法は

function sumsq(v::AbstractVector)
    s = zero(eltype(v))
    for x in v
        s += x ^ 2
    end
    s
end

これは、上記の2つのケースで機能します。しかし、ある意味ではベクトルではない四角形を合計したいかもしれないコレクションがあります。例えば、

julia> sumsq(take(countfrom(1), 100))
ERROR: MethodError: no method matching sumsq(::Base.Take{Base.Count{Int64}})
Closest candidates are:
  sumsq(::Array{Int64,1}) at REPL[8]:2
  sumsq(::AbstractArray{T,1}) at REPL[11]:2

私たちは怠惰な反復可能性の四角形を合計することはできないことを示しています。

もっと一般的な実装は、単純に

function sumsq(v)
    s = zero(eltype(v))
    for x in v
        s += x ^ 2
    end
    s
end

どの場合でもうまくいく:

julia> sumsq(take(countfrom(1), 100))
338350

これは最も慣用的なジュリアコードであり、あらゆる状況に対応できます。他の言語では、型の注釈を削除するとパフォーマンスに影響する可能性がありますが、Juliaではそうではありません。パフォーマンスのためにタイプの安定性のみが重要です。

命令的階乗

長形式の構文は、複数行関数を定義するために使用できます。これは、ループなどの必須の構造を使用する場合に便利です。末尾の式が返されます。たとえば、以下の関数はforループを使用して整数n 階乗を計算forます

function myfactorial(n)
    fact = one(n)
    for m in 1:n
        fact *= m
    end
    fact
end

使用法:

julia> myfactorial(10)
3628800

より長い関数では、使用されるreturn文を見るのが一般的です。 returnステートメントは末尾には必要ではありませんが、それは明瞭にするために使用されることがあります。例えば、上記の関数を書く別の方法は、

function myfactorial(n)
    fact = one(n)
    for m in 1:n
        fact *= m
    end
    return fact
end

これは上記の関数と同じ動作です。

匿名関数

矢印の構文

匿名関数は、 ->構文を使用して作成できます。これは、関数をmap関数などの高次関数に渡す場合に便利です。以下の関数は、 配列 A各数値の2乗を計算します。

squareall(A) = map(x -> x ^ 2, A)

この関数の使用例:

julia> squareall(1:10)
10-element Array{Int64,1}:
   1
   4
   9
  16
  25
  36
  49
  64
  81
 100

複数行の構文

function構文を使用して、複数の匿名関数を作成できます。たとえば、次の例では最初のn数値の階乗を計算しますが、組み込みfactorialではなく無名関数を使用します。

julia> map(function (n)
               product = one(n)
               for i in 1:n
                   product *= i
               end
               product
           end, 1:10)
10-element Array{Int64,1}:
       1
       2
       6
      24
     120
     720
    5040
   40320
  362880
 3628800

ブロック構文を実行する

関数への最初の引数として無名関数を渡すことは非常に一般的であるため、 doブロックの構文があります。構文

map(A) do x
    x ^ 2
end

map(x -> x ^ 2, A)

多くの場合、前者の方がはっきりしている可能性があります。特に、無名関数で多くの計算が行われている場合にはそうです。 doブロック構文は、リソース管理上の理由からファイルの入出力に特に便利です。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow