I created this module
module MyModule
export my_square, my_abs, my_minus
my_square(x::Int64) = x * x
my_abs(x) = (x>=0) ? x : -x
my_add(x,y) = x + y
my_minus(x,y) = x - y
my_multiply(x,y) = x * y
end
but when importing it to use it it throws an error, any solution?
This module got defined in the space of Main hence you need to add a dot . before module name:
julia> using .MyModule
julia> my_abs(-4)
4
Just note that using Main.MyModule will work as well just requires more typing.
If you want rather to write using MyModule (without a dot . nor Main.) you need to put that module into a Julia package. You will find a lot of documentation on creating packages but the simplest steps are:
using Pkg
Pkg.generate("MyModule")
In the folder src you will find MyModule.jl, edit it and paste the module definition.
Now you are ready to do:
julia> Pkg.activate(".\\MyModule") #use the correct path
Activating environment at `MyModule\Project.toml`
julia> using MyModule
Related
I am working on a julia code where I have several files and call functions from these files to a main function called run.jl. Every time I make changes to any one of these files I need to restart the julia REPL which is a bit annoying. Anyway to work around this.
For example
# --------------------------------- run.jl
include("agent_types.jl")
include("resc_funcs.jl")
using .AgentTypes: Cas, Resc
using .RescFuncs: update_rescuers_at_pma!, travel_to_loc
# ... some code
for i = 1:500
update_rescuers_at_pma!(model)
travel_to_loc(model)
end
# ------------------------------ resc_funcs.jl
function travel_to_loc(model)
println(get_resc_by_prop(model, :on_way_to_iz))
for resc_id in get_resc_by_prop(model,:on_way_to_iz)
push!(model[resc_id].dist_traject, model[resc_id].dist_to_agent) #This is just for checking purposes
model[resc_id].dist_to_agent -= model.dist_per_step
push!(model[resc_id].loc_traject, "on_way_to_iz")
end
#If we add new print statement here and execute run.jl it wont print
println(model[resc_id].loc_traject) #new amendment to code
end
But now when I go and update travel_to_loc function for example. I need to restart the julia repl before those changes are reflected. I am wondering if there is a way after you save the file (resc_funcs.jl in this case) those amendments are reflected when you execute run.jl.
The simplest workflow could be the following:
Select some folder to be your current working folder in Julia (eg. by using cd() command from Julia)
Create sample file MyMod.jl
module MyMod
export f1
function f1(x)
x+1
end
end
Add the current folder to LOAD_PATH and load Revise.jl
push!(LOAD_PATH, ".")
using Revise
Load the module and test it:
julia> using MyMod
[ Info: Precompiling MyMod [top-level]
julia> f1(3)
4
Try to edit the file eg. change x+1 to x+3
Run again
julia> f1(3)
6
Notes:
you will still need to restart REPL when your data structures change (you modify a definition of a struct object)
you could generate a full module package using Pkg.generate but I wanted to make things simplified.
I'm using Julia to autograde students' work. I have all of their files Student1.jl, Student2.jl, etc. as separate modules Student1, Student2, etc in a directory that is part of LOAD_PATH. What I want to be able to do works completely fine in the REPL, but fails in a file.
macro Student(number)
return Meta.parse("Main.Student$number")
end
using Student1
#Student(1).call_function(inputs)
works completely fine in the REPL. However, since I'm running this in a script, I need to be able to include the modules with more metaprogramming that is currently not working. I would have thought that the exact same script above would have worked in a file Autograder.jl by calling
#eval(using Student1)
#Student(1).call_function(inputs)
in a module Autograder. But I get either an UndefVarError: Student1 not defined or LoadError: cannot replace module Student1 during compilation depending on how I tweak things.
Is there something small in Julia metaprogramming I'm missing here to make this autograding system work out? Thanks for any advice.
The code just as you have written works for me on julia versions 1.1.0, 1.3.1, 1.5.1, 1.6.0 and 1.7.0. By that I mean, if I add an inputs variable and put your first code block in a file Autograder.jl and run JULIA_LOAD_PATH="modules:$JULIA_LOAD_PATH" julia Autograder.jl with the student modules in the modules directory I get the output of the call_function function in the Student1 module.
However if Autograder.jl actually contains a module then the Student$number module is not required into Main and your macro needs to be modified accordingly:
module Autograder
macro Student(number)
return Meta.parse("Student$number") # or "Autograder.Student$number"
end
inputs = []
#eval(using Student1)
#Student(1).call_function(inputs)
end
Personally I wouldn't use a macro to accomplish this, here is one possible alternative:
student(id) = Base.require(Main, Symbol("Student$(id)"))
let student_module = student(1)
student_module.call_function(inputs)
end
or without modifying the LOAD_PATH:
student(id) = include("modules/Student$(id).jl")
let student_module = student(1)
student_module.call_function(inputs)
end
I am using Cleanide for Clean3.0 programming language.
What I am trying to do is to implement a function that receive name of a directory in my system, and return a list of all the files in that directory.
I don't know if the defintion of such function needs to be like File -> [string] or maybe something else, even that directory is a file maybe this is not the developers of Clean meant...
Thank a lot!
This functionality is not available in the StdEnv environment, but there are two libraries that can help with this:
The Directory library contains a module Directory which has a function getDirectoryContents :: !Path !*env -> (!(!DirError, [DirEntry]), !*env) | FileSystem env.
The Platform library contains a module System.Directory which has a function readDirectory :: !FilePath !*w -> (!MaybeOSError [FilePath], !*w).
In both cases the first argument is a path to the directory and the second argument is the *World, which is the typical way of Clean to perform impure operations (see chapter 9 of the language report).
Code examples
With Directory:
import Directory
Start w
# (dir,w) = getDirectoryContents (RelativePath []) w
= dir
With Platform:
import System.Directory
Start w
# (dir,w) = readDirectory "." w
= dir
I want to use R's mathematical functions as provided in libRmath from Ocaml. I successfully installed the library via brew tap homebrew science && brew install --with-librmath-only r. I end up with a .dylib in /usr/local/lib and a .h in /usr/local/include. Following the Ocaml ctypes tutorial, i do this in utop
#require "ctypes.foreign";;
open Ctypes;;
open Foreign;;
let test_pow = foreign "pow_di" (float #-> int #-> returning float);;
this complains that it can't find the symbol. What am I doing wrong? Do I need to open the dynamic library first? Set some environment variables? After googling, I also did this:
nm -gU /usr/local/lib/libRmath.dylib
which gives a bunch of symbols all with a leading underscore including 00000000000013ff T _R_pow_di. In the header file, pow_di is defined via some #define directive from _R_pow_di. I did try variations of the name like "R_pow_di" etc.
Edit: I tried compiling a simple C program using Rmath using Xcode. After setting the include path manually to include /usr/local/include, Xcode can find the header file Rmath.h. However, inside the header file, there is an include of R_ext/Boolean.h which does not seem to exist. This error is flagged by Xcode and compilation stops.
Noob alert: this may be totally obvious to a C programmer...
In order to use external library you still need to link. There're at least two different ways, either link using compiler, or link even more dynamically using dlopen.
For the first method use the following command (as an initial approximation):
ocamlbuild -pkg ctypes.foreign -lflags -cclib,-lRmath yourapp.native
under premise that your code is put into yourapp.ml file.
The second method is to use ctypes interface to dlopen to open the library. Using the correct types and name for the C function call, this goes like this:
let library = Dl.dlopen ~filename:"libRmath.dylib" ~flags:[]
let test_pow = foreign ~from:library "R_pow_di" (double #-> int #-> returning double)
I wrote
let fact x =
let result = ref 1 in
for i = 1 to x do
result := !result * i;
Printf.printf "%d %d %d\n" x i !result;
done;
!result;;
in a file named "Moduletest.ml", and
val fact : int -> int
in a file named "Moduletest.mli".
But, why don't they work?
When I tried to use in ocaml,
Moduletest.fact 3
it told me:
Error: Reference to undefined global `Moduletest'
What's happening?
Thanks.
OCaml toplevel is linked only with a standard library. There're several options on how to make other code visible to it:
copy-pasting
evaluating from the editor
loading files #use directive
making custom toplevel
loading with ocamlfind
Copy-pasting
This self-describing, you just copy code from some source and paste it into toplevel. Don't forget that toplevel won't evaluate your code until you add ;;
Evaluating from the editor
Where the editor is of course Emacs... Well, indeed it can be any other capable editor, like vim for example. This method is an elaboration of the previous, where the editor is actually responsible for copying and pasting the code for you. In Emacs you can evaluate the whole file with C-c C-b command, or you can narrow it to a selected area with C-c C-r, and the most granular is to use C-c C-e, i.e., evaluate an expression. Although it is slightly buggy.
Loading with #use directive.
This directive accepts a filename, and it will essentially copy and paste the code from the file. Notice, that it won't create a file-module for you/ For example, if you have file test.ml with this contents:
(* file test.ml *)
let sum x y = x + y
then loading it with the #use directive, will actually bring to your scope, sum value:
# #use "test.ml";;
# let z = sum 2 2
You mustn't to qualify sum with Test., because no Test module is actually created. #use directive merely copies the contents of the file to the toplevel. Nothing more.
Making custom toplevels
You can create your own toplevel with your code compiled in. It is an advanced theme, so I will skip it.
Loading libraries with ocamlfind
ocamlfind is a tool that allows you to find and load libraries, installed on your system, into your toplevel. By default, toplevel is not linked with any code except standard library. Even, not all parts of the library are actually linked, e.g., Unix module is not available, and needed to be loaded explicitly. There're primitive directives that can load any library, like #load and #include, but they are not for a casual user, especially if you have excellent ocamlfind at your disposal. Before using it, you need to load it, since it is also not available by default. The following command, will load ocamlfind and add few new directives:
# #use "topfind";;
In a process of loading it will show you a little hint on how to use it. The most interesting directive, that is added is #require. It accepts a library name, and loads (i.e., links) its code into toplevel:
# #require "unix";;
This will load a unix library. If you're not sure, about the name of the library you can always view all libraries with a #list command. The #require directive is clever and it will automatically load all dependencies of the library.
If you do not want to type all this directives every time you start OCaml top-level, then you cam create .ocamlinit file in your home directory, and put them there. This file will be loaded automatically on a top-level startup.
I have tested your code and it looks fine. You should "load" it from the OCaml toplevel (launched from the same directory as your .ml and .mli files) in the following way:
# #use "Moduletest.ml";;
val fact : int -> int = <fun>
# fact 4;;
4 1 1
4 2 2
4 3 6
4 4 24
- : int = 24