Абстрактная типизация и множественная отправка для функций в julia - PullRequest
3 голосов
/ 07 августа 2020

Я хочу, чтобы объекты взаимодействовали с конкретными c взаимодействиями в зависимости от их типа.

Пример проблемы: у меня четыре частицы, две из которых относятся к типу A, а 2 - к типу B., когда взаимодействуют типы A I хочу использовать функцию

function interaction(parm1, parm2)
    return parm1 + parm2
end

при взаимодействии типа B Я хочу использовать функцию

function interaction(parm1, parm2)
        return parm1 * parm2
    end

, когда тип A взаимодействует с типом BI хочу использовать функцию

function interaction(parm1, parm2)
        return parm1 - parm2
    end

Эти функции намеренно чрезмерно просты.

Я хочу вычислить простое суммирование, которое зависит от парных взаимодействий:

struct part
    parm::Float64
end

# part I need help with:
# initialize a list of length 4, where the entries are `struct part`, and the abstract types
# are `typeA` for the first two and `typeB` for the second two. The values for the parm can be
# -1.0,3, 4, 1.5 respectively

energy = 0.0
for i in range(length(particles)-1)
    for j = i+1:length(particles)
        energy += interaction(particles[i].parm, particles[j].parm)
    end
end

println(energy)

при условии использования параметров particle[1].parm = -1, particle[2].parm = 3, particle[3].parm = 4, particle[4].parm = 1.5, энергия должна учитывать взаимодействия

(1,2) = -1 + 3 = 2
(1,3) = -1 - 4 = -5
(1,4) = -1 - 1.5 = -2.5
(2,3) = 3 - 4 = -1
(2,4) = 3 - 1.5 = 1.5
(3,4) = 4 * 1.5 = 6

energy = 1

Выполнение этого с помощью if statements почти тривиально, но не расширяемо. Я после чистого, аккуратного подхода Джулии ...

Ответы [ 2 ]

4 голосов
/ 07 августа 2020

Вы можете это сделать (я использую простейшую форму реализации, так как в данном случае этого достаточно и, надеюсь, ясно, что произойдет):

struct A
    parm::Float64
end

struct B
    parm::Float64
end

interaction(p1::A, p2::A) = p1.parm + p2.parm
interaction(p1::B, p2::B) = p1.parm * p2.parm
interaction(p1::A, p2::B) = p1.parm - p2.parm
interaction(p1::B, p2::A) = p1.parm - p2.parm # I added this rule, but you can leave it out and get MethodError if such case happens

function total_energy(particles)
    energy = 0.0
    for i in 1:length(particles)-1
        for j = i+1:length(particles)
            energy += interaction(particles[i], particles[j])
        end
    end
    return energy
end

particles = Union{A, B}[A(-1), A(3), B(4), B(1.5)] # Union makes sure things are compiled to be fast

total_energy(particles)
0 голосов
/ 07 августа 2020

Я понятия не имею, как это сделать на вашем языке, но вам нужен аналог того, что мы называем шаблоном стратегии в объектно-ориентированном программировании. Стратегия - это подключаемый многоразовый алгоритм. В Java я бы создал интерфейс вроде:

interface Interaction<A, B>
{
    double interact(A a, B b)
}

Затем реализовал бы это три раза и повторно использовал бы эти части везде, где вам нужно взаимодействовать друг с другом. Другой метод может взять взаимодействие и использовать его, не зная, как оно реализовано. Я думаю, это тот эффект, который вам нужен. Извините, я не знаю, как перевести на ваш диалект.

...