本文介绍了我可以写“在任何可能的情况下"工作的Julia方法吗?像C ++模板函数一样?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

rand适用于范围:

rand(1:10)

我想使randArray一起使用,并且将所有可索引并具有length的内容都使用:

I'd like to make rand work with Array, and anything that is indexable and has length:

import Base.Random
rand(thing) = thing[rand(1:length(thing))]

array = {1, 2, 3}
myRand(array)

range = 1:8
myRand(range)

tupple = (1, 2, 3, "a", "b", "c")
myRand(tupple)

…但是如果我尝试这样做,我的实现堆栈会溢出,大概是因为它是完全通用的,并且与传递的所有内容都匹配,所以它最终会自行调用?

… but if I try this, my implementation stack overflows, presumably because it is completely general and matches everything passed, so it ends up calling itself?

是否可以解决此问题?我想更好地了解Julia的多态函数,而不是为此特殊的(可能很愚蠢的)函数专门知识解决问题.

Is there a way to fix this? I want to better understand Julia's polymorphic functions rather than get a fix for this particular (probably silly) function specialisation.

是否还有一个工具可以发现可用的各种实现,并调试将使用特定参数调用的实现?

Is there also a tool to discover the various implementations that are available, and debug which will be called with particular arguments?

好的,有些挖掘.这很有趣...

Okay, some digging. This is interesting…

我将开始一个新的REPL,并且:

I'll start up a fresh REPL, and:

julia> import Base.Random

julia> rand(thing) = thing[rand(1:length(thing))]
rand (generic function with 1 method)

julia> rand({1,2,3})
ERROR: stack overflow
 in rand at none:1 (repeats 80000 times)

…哦,亲爱的,那是我正在谈论的递归调用和堆栈溢出.

…Oh dear, that's the recursive call and stack overflow I was talking about.

但是,请注意这一点.我杀死了朱莉娅,然后重新开始REPL.这次我import Base.Random.rand:

But, watch this. I kill Julia and start the REPL again. This time I import Base.Random.rand:

julia> import Base.Random.rand

julia> rand(thing) = thing[rand(1:length(thing))]
rand (generic function with 33 methods)

julia> rand({1,2,3})
3

它有效–它将我的新实现添加到所有其他实现中,并选择了正确的实现.

It works – it added my new implementation to all the others, and picked the right one.

因此,我的第一个问题的答案似乎是–它确实有效".太神奇了怎么运作的?!

So, the answer to my first question seems to be – "it just works". Which is amazing. How does that work?!

但是关于模块的问题听起来没那么有趣,为什么import Base.Random不会引入rand方法或给出错误,而import Base.Random.rand却给出错误.

But there's a slightly less interesting sounding question about modules, and why import Base.Random doesn't pull in the rand method or give an error, but import Base.Random.rand does.

推荐答案

方法扩展

正如某些人指出的那样,Julia让您扩展函数:您可以为不同类型的函数提供不同的功能(请参见文档的这一部分).

Method extension

As some have pointed, Julia let you extend functions: you can have functions that work differently for different types (see this part of the documentation).

例如:

f(x) = 2
f(x::Int) = x

在此示例中,我们有一个函数的版本(或方法),当(且仅当)参数的类型为Int时,才调用该函数.第一个叫否则.

In this example, we have a version (or method) of the function that is called if (and only if) the argument is of the type Int. The first one is called otherwise.

我们说我们已经扩展了f函数,现在它有2种方法.

We say that we have extended the f function, and now it has 2 methods.

那么,您想要的是扩展rand函数.

What you want, then, is to extend the rand function.

您希望您的rand函数(如果使用未被其他方法捕获的参数调用)执行thing[rand(1:length(thing))].如果正确完成,您将调用应用于Range对象的rand方法,因为您将1:length(thing)作为参数传递.

You want your rand function, if called with a argument that was not caught by other methods, to execute thing[rand(1:length(thing))]. If done correctly, you would call the rand method that is applied to a Range object, since you are passing 1:length(thing) as argument.

尽管存在缺陷(如果thing没有长度,例如复数?),我会说您的第一次尝试是非常合理的.

Although flawed (what if thing doesn't have a length, e.g. a complex number?), I would say your first attempt was very reasonable.

问题:rand无法在程序的第一个版本上扩展.根据这部分文档 ,编写import Base.Random不能使rand可用于方法扩展.

The problem: rand couldn't be extended on the first version of your program. According to this piece of documentation, writing import Base.Random doesn't make rand available for method extension.

在尝试扩展rand时,实际上覆盖了 rand函数.此后,当您调用函数rand时,只有您的方法!

While trying to extend rand, you actually overwrite the rand function. After this, when you call the function rand, there is only your method!

请记住,您所依赖的事实是另外定义了范围方法(例如rand(1:10)),并且给出了预期的结果.发生的事情是该方法被您的方法覆盖,因此再次(递归)调用了您的方法.

Remember, you were relying on the fact that a method for ranges (e.g. rand(1:10)) was defined elsewere, and that it gave the result you expected. What happened was that this method was overwritten by yours, so your method is called again (recursively).

解决方案:导入rand,例如扩展名.您可以在文档表格上看到它.

The solution: import rand such as it is available to extension. You can see that on the table on the documentation.

请注意,您的第二个程序(带有import Base.Random.rand的程序)和Colin的程序(带有importall Base.Random的程序)正是这样做的.这就是它们起作用的原因.

Notice that your second program (the one with import Base.Random.rand) and Colin's program (the one with importall Base.Random) did exactly that. That's why they work.

请记住,哪些方法可以扩展,哪些方法不可用,如果文档不够清晰,将欢迎报告错误(或修复).

Keep in mind what methods are or are not available for extension, and if the documentation isn't clear enough, a bug report (or maybe a fix) will be welcomed.

这篇关于我可以写“在任何可能的情况下"工作的Julia方法吗?像C ++模板函数一样?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-01 22:39