2024年Clojure问卷调查!中分享你的想法。

欢迎!请参阅关于页面了解更多关于如何使用它的信息。

+1
ClojureCLR
    static void Main()
    {
        try
        {
            IFn load = clojure.clr.api.Clojure.var("clojure.core", "load");

            // Below code line seems to expect clojure code (non-compiled) in path
            // bin\Debug\net7.0\clojure\hello.test.clj
            // 
            // OR a compiled dll: 
            //
            // from folderstructure 
            // ./clojure/hello/test.clj
            // > clojure.compile clojure.hello.test
            // 
            // with content in clj file like:
            //   (ns clojure.hello.test)
            //   (defn output[] "ninja")
            var r = load.invoke("hello.test"); 
            IFn helloFn = clojure.clr.api.Clojure.var("clojure.hello.test", "output");
            var result = helloFn.invoke();
            Console.WriteLine("Calling compiled clj from C#, Got: " + result);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
我的问题
有没有一个简单的示例,说明如何从C#代码调用clojure函数,就像上面那样?

有没有任何关于如何考虑命名空间和文件夹结构的一般文献,当我们尝试从C#interop到clojure时?

我现在的主要目标是娱乐自己,并最终使用nREPL + CIDER运行点东西。
我尝试加载(使用 load.invoke)(使用load.invoke) clojure.tools.nrepl,但对在哪里放置dll以及如何重新命名它感到困惑?!

// 以下代码
IFn load = clojure.clr.api.Clojure.var("clojure.core", "load");
var r = load.invoke("tools.nrepl");

我输出了RT.cs静态FileInfo FindFile(string path, string filename)
probePath 属性发现
... 是我的框架文件夹的绝对路径(net7.0)

...\net7.0\clojure\tools.nrepl.cljr
...\net7.0\bin\clojure\tools.nrepl.cljr
...\net7.0\clojure\tools.nrepl.cljr
...\net7.0\clojure\tools.nrepl.cljc
...\net7.0\bin\clojure\tools.nrepl.cljc
...\net7.0\clojure\tools.nrepl.cljc
...\net7.0\clojure\tools.nrepl.clj
...\net7.0\bin\clojure\tools.nrepl.clj
...\net7.0\clojure\tools.nrepl.clj
...\net7.0\clojure.tools.nrepl.cljr.dll
...\net7.0\bin\clojure.tools.nrepl.cljr.dll
...\net7.0\clojure.tools.nrepl.cljr.dll
...\net7.0\clojure.tools.nrepl.cljc.dll
...\net7.0\bin\clojure.tools.nrepl.cljc.dll
...\net7.0\clojure.tools.nrepl.cljc.dll
...\net7.0\clojure.tools.nrepl.clj.dll
...\net7.0\bin\clojure.tools.nrepl.clj.dll
...\net7.0\clojure.tools.nrepl.clj.dll
错误:无法在加载路径上找到 clojure/tools.nrepl,其扩展名为 .cljr、.cljc、.clj、.cljr.dll、.cljc.dll 或 .clj.dll。

这些都不匹配由nuget提供的 clojure.tools.nrepl.dll
操作:重命名
clojure.tools.nrepl.dll -> clojure.tools.nrepl.clj.dll

然后dll被拾取,但无法加载
clojure.lang.Compiler.AssemblyInitializationException: '无法找到初始化器
对于 clojure.tools.nrepl, Version=0.1.0.0, Culture=neutral,
键盘符号= null.clojure/tools/nrepl'

2 个回答

0

clojurians 发布

0

我没看到你调用 Assembly.Load 的地方,这是必需的。尝试在 Program.cs 中这样做

using clojure.lang;
using System.Reflection;

// start up Clojure runtime including compiler
RT.Init();

// make .cljr file resources available from DLL
Assembly.Load("clojure.tools.nrepl");
Assembly.Load("clojure.tools.reader");

// compile nREPL lib
var ns = "clojure.tools.nrepl";
RT.var("clojure.core", "require").invoke(Symbol.intern(ns));

// create nREPL server (default port is 1667)
var startServer = RT.var(ns, "start-server!");
var server = startServer.invoke();

// allow exit on Ctrl-C by shutting down server
var stopServer = RT.var(ns, "stop-server!");
Console.CancelKeyPress += (_, _) => stopServer.invoke(server);

下面是一个合适的 example.csproj 文件

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Clojure" Version="1.12.0-alpha8" />
    <PackageReference Include="clojure.tools.nrepl" Version="0.1.0-alpha1" />
  </ItemGroup>

</Project>

我在 Ubuntu 22.04 上使用 dotnet 7.0.114。在空目录中放入这两个文件后,只需运行

dotnet restore
dotnet run

祝您玩得开心!

感谢这个例子,它非常好用。也许这也让我对 Clojure 的“内部”有了更深的理解:(RT.init, RT.var 等。)。
我认为维基百科可以像您上面那样添加更多清晰的例子来改进。
https://github.com/clojure/clojure-clr/wiki/Using-ClojureCLR-in-a-C%23-project

我会尝试学习更多,也许有朝一日会做出一些贡献...
...