如何在 Julia 中使用开放式类型编写 Trait? [英] How can I write a Trait in Julia with open-ended types?

查看:18
本文介绍了如何在 Julia 中使用开放式类型编写 Trait?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是为了简化我提出的问题的一部分 这里:

This is an attempt to simplify one part of the question I asked here:

我想编写一些代码,保证在满足特定条件的类型上工作.假设今天我写了一些代码:

I want to write some code that is guaranteed to work on types that meet certain criteria. Let's say today I write some code:

immutable Example
    whatever::ASCIIString
end
function step_one(x::Example)
    length(x.whatever)
end
function step_two(x::Int64)
    (x * 2.5)::Float64
end
function combine_two_steps{X}(x::X)
    middle = step_one(x)
    result = step_two(middle)
    result
end
x = Example("Hi!")
combine_two_steps(x)

运行这个工程:

julia> x = Example("Hi!")
Example("Hi!")

julia> combine_two_steps(x)
7.5

然后改天我又写了一些代码:

Then another day I write some more code:

immutable TotallyDifferentExample
    whatever::Bool
end
function step_one(x::TotallyDifferentExample)
    if x.whatever
        "Hurray"
    else
        "Boo"
    end
end
function step_two(x::ASCIIString)
    (Int64(Char(x[end])) * 1.5)::Float64
end

你知道吗,我的通用合并函数仍然有效!

And what do you know, my generic combine function still works!

julia> y = TotallyDifferentExample(false)
TotallyDifferentExample(false)

julia> combine_two_steps(y)
166.5

万岁!但是,假设现在是深夜,我正试图在第三个示例中再次执行此操作.我记得实现step_one,但是忘记实现step_two

Hurray! But, say it's a late night and I'm trying to do this AGAIN on a third example. I remember to implement step_one, but I forget to implement step_two!

immutable ForgetfulExample
    whatever::Float64
end
function step_one(x::ForgetfulExample)
    x.whatever+1.0
end

现在当我运行它时,我会得到一个运行时错误!

Now when I run this, I'm going to get a run-time error!

julia> z = ForgetfulExample(1.0)
ForgetfulExample(1.0)

julia> combine_two_steps(z)
ERROR: MethodError: `step_two` has no method matching step_two(::Float64)

现在,我为一位经理工作,如果我遇到运行时错误,他会杀了我.所以为了挽救我的生命,我需要做的是编写一个 Trait,它基本上说如果类型实现了这个 trait,那么调用 combine_two_steps 是安全的."

Now, I work for a manager who will KILL ME if I ever get a run-time error. So what I need to do to save my life is to write a Trait that essentially says "if the type implements this trait, then it's safe to call combine_two_steps."

我想写一些类似的东西

using Traits
@traitdef ImplementsBothSteps{X} begin
    step_one(X) -> Y
    step_two(Y) -> Float64
end
function combine_two_steps{X;ImplementsBothSteps{X}}(x::X)
    middle = step_one(x)
    result = step_two(middle)
    result
end

b/c 那么我就知道 如果 combine_two_steps 曾经调度,然后它 运行不会引发这些方法不存在的错误.

b/c then I'd know that if combine_two_steps is ever dispatched, then it will run without raising an error that these methods don't exist.

等价地,istrait(ImplementsBothSteps{X})(为真)等价于 combine_two_steps 将运行而不会出现所需方法不存在错误.

Equivalently, istrait(ImplementsBothSteps{X}) (being true) is equivalent to combine_two_steps will run without error-from-nonexistence-of-required-methods.

但是,众所周知,我不能使用该特征定义,因为 Y 没有任何意义.(事实上​​,奇怪的是代码编译没有错误,

But, as everybody knows, I can't use that trait definition, because Y has no meaning. (In fact, oddly enough the code compiles without error,

julia> @traitdef ImplementsBothSteps{X} begin
           step_one(X) -> Y
           step_two(Y) -> Float64
       end

julia> immutable Example
           whatever::ASCIIString
       end

julia> function step_one(x::Example)
           length(x.whatever)::Int64
       end
step_one (generic function with 1 method)

julia> function step_two(x::Int64)
           (x * 2.5)::Float64
       end
step_two (generic function with 1 method)

julia> istrait(ImplementsBothSteps{Example})
false

但类型不满足特征,即使某些 Y 存在方法.)我的第一个想法是我可以将 Y 更改为 之类的东西任意

but the types don't satisfy the trait even though the methods exist for some Y.) My first thought is I can change Y to something like Any

using Traits
@traitdef ImplementsBothSteps{X} begin
    step_one(X) -> Any
    step_two(Any) -> Float64
end

但这也失败了 b/c Any 真的应该是类似 Some 的东西,而不是字面上的 Any 类型(因为我从未实现过可以将任何类型作为输入的方法 step_two),而是在两行之间共享的某些特定类型!

but this fails too b/c the Any really is supposed to be something like Some, not literally the Any type (since I never implemented a method step_two that could take any type as input), but some particular type that's shared across both lines!

所以,问题是:在这种情况下你会怎么做?您想传递一个规范"(此处以 Trait 表示的合同的形式),以保证任何符合规范的程序员都能够使用您的函数 combine_two_steps,但是该规范在其定义中本质上具有一个存在量词.

So, the question is: what would you do in this situation? You want to pass around a "spec" (here in the form of the contract expressed by the Trait) such that any programmer anywhere who meets the spec is guaranteed to be able to use your function combine_two_steps, but the spec essentially has an existential quantifier in its definition.

有解决方法吗?编写规范"的更好方法(例如不要使用 Traits,使用其他东西"?)等等.

Is there a workaround? A better approach to writing the "spec" (e.g. "Don't use Traits, use something else"?) Etc.

顺便说一句,这听起来可能有点做作,但上面链接的问题和这个问题在我正在进行的项目中经常出现.我基本上陷入了由这个问题引起的障碍,并且有一些丑陋的变通办法可以逐案解决,但没有办法解决一般情况.

By the way, it may sound contrived, but the above-linked question and this question are coming up regularly in a project I'm working on. I'm essentially stuck at a roadblock caused by this problem and have ugly workarounds that work case-by-case, but no approach to the general case.

推荐答案

概括我使用 Any 问题中的建议实际上也可以工作,尽管它很丑陋并且并没有真正达到观点.假设你已经实现了方法

Generalizing on the suggestion in my question of using Any actually can work also, although it's ugly and doesn't really get to the point. Suppose you have already implemented methods

step_one(X) -> Y
step_two(Y) -> Z

那么你可以把特质写成

@traitdef implements_both_steps begin
    step_one(X) -> Any
    step_two(Any) -> Z
end

只需添加一个虚拟方法

function step_two(x::Any)
    typeof(x)==Y ? step_two(x::Y) : error("Invalid type")
end

这也可以封装在一个宏中,以节省重复模式的时间,然后一旦实现该方法,特征就会得到满足.这是我一直在使用(并且有效)b/c 的 hack,它相当简单,但解决方案不符合我的问题.

This can be wrapped up in a macro as well to save on repeating the pattern, and then once that method is implemented the trait is satisfied. It's a hack that I've been using (and that works) b/c it's fairly straightforward, but the solution is not in the spirit of my question.

这篇关于如何在 Julia 中使用开放式类型编写 Trait?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆