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

查看:27
本文介绍了如何用开放式类型在 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.

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

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天全站免登陆