如何在模块中声明外部函数

时间:2021-01-18 14:49:38

标签: julia

我在 Julia 模块中编写了以下算法

module two_algo

export two

function two(type)
  a = construct(type)
  b = construct(type)
  result = construct(type)
  unity(a)
  unity(b)
  add(a,b,result)
  return result
end

end

有一次我在模块外定义了这个算法,它可以编译并可以分派到任何定义了构造、统一和添加方法的类型。但是在一个模块中它不会编译。它不知道如何找到构造、统一和添加。我不想从某个特定模块导入它们,因为我可能有许多模块,例如每个模块都定义了构造、统一和添加。我需要做什么才能编译它?在我过去的 C/C++ 时代,我记得做过一些像声明“extern 构造”这样简单的事情。模块内。我真的希望我可以让 two() 函数采用单一类型,而不是传入实现构造、统一和添加的函数。理想情况下,我也想避免泛型。感谢您的指点。

2 个答案:

答案 0 :(得分:1)

首先,让我说您可能不需要这里的模块:将您的项目组织在单独的文件中(以便您轻松地在源代码中导航)可能是一个好主意,但是拥有单独的模块会带来一些复杂性,这可能会此处不需要(例如,不存在需要使用单独模块/命名空间来避免的名称冲突风险)。

话虽如此,这里组织事物的一种方法是使辅助函数(如 unityadd)与使用它们的通用算法属于同一个模块。这是一个最小的例子:

module Algo
export algo

# These functions are only declared; they have no method
function unity end
function add end

function algo(T)
    a = unity(T)
    add(a, a)
end

end

定义新类型的代码的其他部分然后必须扩展模块中的函数以添加特定方法:

using .Algo

struct MyType
    val :: Int
end

# Explicitly extend the `unity` and `add` function from module `Algo`
# (instead of merely defining new functions with the same name
Algo.unity(::Type{MyType}) = MyType(1)
Algo.add(a::MyType, b::MyType) = MyType(a.val + b.val)

这应该按预期工作:

julia> Algo.algo(MyType)
MyType(2)



编辑:一个更复杂的组织允许通过在“基本”模块中声明泛型函数来将所有算法(也可能是所有类型)相互隔离,所有其他模块都知道关于:

module AlgoBase
    export unity, add
    
    function unity end
    function add end
end

module Algo1
    using ..AlgoBase  # allows using unity and add    
    export algo1

    function algo1(T)
        a = unity(T)
        add(a, a)
    end
end

module Types1
    using ..AlgoBase
    export Type1
    
    struct Type1
        val :: Int
    end

    # Explicitly extend the `unity` and `add` function from module `AlgoBase`
    # (instead of merely defining new functions with the same name
    AlgoBase.unity(::Type{Type1}) = Type1(1)
    AlgoBase.add(a::Type1, b::Type1) = Type1(a.val + b.val)
end

using .Algo1
using .Types1

algo1(Type1)

这或多或少是 Julia 生态系统的整个部分的设计方式,多个包协作提供与给定领域相关的算法,而不必相互依赖:它们只需要了解一个“基础”包(例如 StatsBase,它声明了许多有用的构建块,类型可以实现,算法可以使用)。然而,这样的架构通常用于使整个(和不相关的)包协作,即不是真正以单个包内的子模块的规模。赞一个

答案 1 :(得分:0)

这是对弗朗索瓦回答的轻微修改,解决了我的问题。我仍然接受他的回答,因为他做了大部分的发现和工作。

module UnityBase
    export unity
    
    function unity end
end

module AddBase
    export add
    
    function add end
end

module TwoAlgo
    using ..UnityBase, ..AddBase
    export two

    function two(T)
        a = unity(T)
        add(a, a)
    end
end

module MyTypeMod
    using ..AddBase, ..UnityBase
    export MyType
    
    struct MyType
        val :: Int
    end

    UnityBase.unity(::Type{MyType}) = MyType(1)
    AddBase.add(a::MyType, b::MyType) = MyType(a.val + b.val)
end

using .TwoAlgo
using .MyTypeMod

println(two(MyType))