Trilhas
/
Julia
Julia
/
Programa
/
Funções
Fu

Funções em Julia

2 exercícios

Sobre Funções

O conceito Basics apresentou duas formas de definir uma função.

De modo mais geral, a forma multilinha:

function muladd(x, y, z)
    x * y + z
end

A forma de "atribuição", ou de "linha única", para definições curtas:

muladd(x, y, z) = x * y + z

Em uma terceira forma, ainda mais curta, é possível criar uma função curta e de uso único sem um nome:

julia> map(x -> 2x, 1:3)
4-element Vector{Int64}:
 2
 4
 6

julia> map((x, y) -> x * y, 1:3, 4:6)
3-element Vector{Int64}:
  4
 10
 18

Nesse caso, x -> 2x é uma "função anônima". Isso equivale ao que outras linguagens chamam de "função lambda".

Repare que vários argumentos precisam de parênteses, como em (x, y) -> x * y.

Funções anônimas são comuns no código Julia, especialmente quando combinadas com funções de ordem superior, como map() e filter().

Argumentos de função

Até agora, no syllabus, vimos apenas funções que têm um número exato de argumentos e exigem que as chamadas forneçam todos eles, na ordem correta. Isso seria limitante e inconveniente, então existem várias outras opções.

Argumentos opcionais

Como muitas linguagens, Julia permite que as definições de função forneçam valores padrão para argumentos individuais.

A chamada de função pode então fornecer um valor para esse argumento, ou omiti-lo e usar o valor padrão.

julia> f(x, y=10) = x * y
f (generic function with 2 methods)

julia> f(2, 3)
6

julia> f(2)
20

Todos os argumentos sem valor padrão devem vir antes de qualquer argumento com valor padrão, o que significa que f(x=2, y) seria inválido.

Argumentos de palavra-chave

Todos os exemplos até aqui usam positional arguments, em que os valores fornecidos em uma chamada de função devem corresponder à ordem dos argumentos correspondentes na definição da função.

Como muitas linguagens, Julia também permite keyword arguments. As chamadas de função precisam especificar o nome do argumento, mas vários argumentos de palavra-chave podem então ser especificados em qualquer ordem.

Uma característica marcante de Julia é que os argumentos de palavra-chave (se houver) na definição da função precisam ser precedidos por um ponto e vírgula ;, para separá-los de quaisquer argumentos posicionais. Uma chamada de função pode usar ; ou , entre o último argumento posicional e o primeiro argumento de palavra-chave.

julia> b(x; y) = x + y
b (generic function with 1 method)

julia> b(2, y=3)
5

# keyword is required when calling
julia> b(2, 3)
ERROR: MethodError: no method matching b(::Int64, ::Int64)
The function `b` exists, but no method is defined for this combination of argument types.

Os valores padrão podem ser especificados opcionalmente, exatamente como para os argumentos posicionais.

É comum acabarmos com uma sintaxe como myarg=myarg dentro de uma chamada de função, quando uma variável com o mesmo nome do parâmetro já foi calculada antes. Uma sintaxe abreviada é permitida nessa situação:

julia> width = 4.0
4.0

julia> height = √ width
2.0

julia> area(; width, height) = width * height
area (generic function with 1 method)

# repetition
julia> area(; width=width, height=height)
8.0

# shorthand form
julia> area(; width, height)
8.0

Splat e slurp

Esses são os nomes padrão de um aspecto útil da sintaxe de Julia, caso você tenha ficado curioso. Ambos se referem ao operador ....

Splat

O splat é usado em chamadas de função, para expandir coleções em valores individuais exigidos pela função.

Talvez seja mais fácil demonstrar do que explicar:

julia> fxyz(x, y, z) = x * y * z
fxyz (generic function with 1 method)

julia> xyz = [2, 3, 4]
3-element Vector{Int64}:
 2
 3
 4

# Using the vector directly in a function call is invalid
julia> fxyz(xyz)
ERROR: MethodError: no method matching fxyz(::Vector{Int64})
The function `fxyz` exists, but no method is defined for this combination of argument types.

# splatting converts the vector to 3 numbers, used as positional arguments
julia> fxyz(xyz...)
24

Algumas "chamadas de função" ficam escondidas por açúcar sintático, então o splat também pode ser usado de formas menos óbvias.

Por exemplo, a atribuição múltipla usa internamente uma função construtora de tuplas:

julia> first, rest... = [1, 2, 3, 4]
4-element Vector{Int64}:
 1
 2
 3
 4

julia> first
1

julia> rest
3-element Vector{Int64}:
 2
 3
 4

Argumentos de palavra-chave também podem ser fornecidos por splat, normalmente usando uma named tuple. Um Dict também funciona, mas as chaves precisam ser símbolos (strings não funcionam aqui).

# function with 3 keyword arguments
julia> fabc(; a, b, c) = a + b + c
fabc (generic function with 1 method)

# named tuple
julia> abc_nt = (a=2, b=3, c=4)
(a = 2, b = 3, c = 4)

# there are no positional arguments, so need to use ; before kw argument
julia> fabc(;abc_nt...)
9

# Dict
julia> abc_dict = Dict(:a=>2, :b=>3, :c=>4)
Dict{Symbol, Int64} with 3 entries:
  :a => 2
  :b => 3
  :c => 4

julia> fabc(;abc_dict...)
9
Slurp

O slurp é usado na definição da função, para empacotar um número arbitrário de valores individuais em uma coleção.

julia> f_more(i, j, more...) = i + j + sum(more)
f_more (generic function with 1 method)

julia> f_more(1, 3, 5, 7, 9, 11)
36

O nome do argumento capturado pelo slurp (nesse caso, more) não importa. O tipo dessa variável é escolhido pelo compilador, mas, para argumentos posicionais, provavelmente será tuple ou algo parecido.

Argumentos de palavra-chave também podem passar por slurp, gerando um Dict (ou algo parecido).

julia> f_kwslurp(x, y; switches...) = :mult in keys(switches) ? x * y : x + y
f_kwslurp (generic function with 1 method)

julia> f_kwslurp(5, 6; mult=true)
30

julia> f_kwslurp(5, 6)
11

Qualquer argumento de palavra-chave pode ser usado na chamada. Cabe à definição da função decidir a quais palavras-chave responder e quais ignorar.

Editar via GitHub O link abre em uma nova janela ou aba

Aprenda Funções

A prática está bloqueada

Desbloqueie mais 1 exercício para praticar Funções