Функции как инфиксные операторы без канала? - PullRequest
4 голосов
/ 07 марта 2020

Читая книгу на Julia Я нашел следующий пример кода:

Автор создает тип

type Student
    name::String
end

создает экземпляр этого типа

antony = Student("Antony Miller")

и затем проверяет тип antony двумя различными способами

isa(antony, Student)
true

antony isa Student
true

Это замечательный способ использования синтаксиса для обеспечения читабельности кода. Однако как здесь можно использовать функцию isa() в качестве инфиксного оператора? Я бы предположил, что возможно следующее ...

antony |> isa(Student)
true

... так как канал (|>) использует объект слева в качестве первого аргумента в функции справа. Но почему можно опустить трубу в примере дальше? И могу ли я использовать то же поведение в своих собственных функциях, чтобы сделать код более читабельным (мне бы очень хотелось)?

Ответы [ 2 ]

6 голосов
/ 07 марта 2020

Как объяснено в этом ответе: Пользовательский инфиксный оператор , у Джулии есть фиксированный набор инфиксных операторов. Вы можете перегружать операторы, но вы не можете определять новые инфиксные операторы.

isa входит в этот предопределенный набор инфиксных операторов.

Однако вы можете имитировать инфиксные операторы с макросами (также указано в связанной ветке). Вы можете увидеть пример в DiffEq документах .

2 голосов
/ 08 марта 2020

Возможно сделать семантику трубопровода, которую вы просили, для работы. Предположим, у нас есть функция двух аргументов

rel_diff(x, y) = (x - y)/(x + y) 

Мы можем определить

rel_diff(y) = x -> rel_diff(x, y)

, чтобы

julia> 1 |> rel_diff(2)
-0.3333333333333333

Я не думаю, что это очень эстетично , но вы могли бы.


Другой альтернативой может быть этот трюк:

struct Infixed{X, F <: Function}
    x::X
    f::F
end

(|)(args...) = Base.:(|)(args...)
(|)(x, f::Function) = Infixed(x, f)
(|)(xf::Infixed, y) = xf.f(xf.x, y)

, и теперь мы можем сделать

julia> 1 |rel_diff| 2
-0.3333333333333333

Обратите внимание, что это основано на затенении базового определения | чтобы мы не совершали пиратство типов. Это не будет работать в глобальной области видимости REPL, если вы уже использовали |, но будет работать, если вы создадите новую локальную область, например, с let или внутри тела функции.

...