Una objeción frecuente a Julia es que Python y R llevan décadas acumulando librerías. No es una objeción tonta. La respuesta de Julia es directa: puedes llamar a código Python, R y C desde Julia sin salir del lenguaje. No como un truco marginal, sino como parte del diseño. Eso significa que puedes aprovechar cualquier librería de esos ecosistemas mientras el código crítico corre en Julia nativo.
PyCall.jl: llamar a Python desde Julia
PyCall.jl incrusta un intérprete de Python en el proceso de Julia. La conversión de tipos entre Python y Julia es automática para los tipos habituales: arrays de NumPy se convierten a arrays de Julia sin copia, los diccionarios de Python se convierten a Dict de Julia, y así sucesivamente.
using PyCall
# Importar un módulo de Python
np = pyimport("numpy")
sklearn = pyimport("sklearn.linear_model")
# Usar numpy desde Julia
arr_py = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
media = np.mean(arr_py)
println("Media numpy: $media")
# Arrays numpy <-> Julia: conversión automática sin copia
arr_julia = [1.0, 2.0, 3.0, 4.0, 5.0]
arr_np_from_julia = PyArray(arr_julia) # vista sin copia
# Scikit-learn desde Julia
X_train = np.array([[1.0, 2.0], [2.0, 3.0], [3.0, 4.0]])
y_train = np.array([1.0, 2.0, 3.0])
model = sklearn.LinearRegression()
model.fit(X_train, y_train)
println("Coeficientes: ", model.coef_)
# Código Python inline con @py_str
py"""
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2*np.pi, 100)
plt.plot(x, np.sin(x))
plt.savefig('sin_desde_julia.png')
"""
# También puedes definir funciones Python y llamarlas desde Julia
py"""
def cuadrado_py(x):
return x ** 2
"""
cuadrado_py = py"cuadrado_py"
resultado = cuadrado_py(5)
CondaPkg.jl: gestionar el entorno Python
Para que PyCall use las librerías correctas sin conflictos con el Python del sistema, CondaPkg.jl gestiona un entorno conda local al proyecto Julia:
using CondaPkg
# Añadir dependencias Python (se guardan en CondaPkg.toml)
CondaPkg.add("scikit-learn")
CondaPkg.add("pandas")
CondaPkg.add("matplotlib")
# Julia instala y gestiona el entorno automáticamente
# No hay que activar entornos manualmente
RCall.jl: llamar a R desde Julia
RCall.jl funciona de forma similar a PyCall pero para el ecosistema R. Especialmente útil para acceder a paquetes estadísticos que no tienen equivalente en Julia, como ciertos modelos de estadística bayesiana o gráficos de ggplot2:
using RCall
# Ejecutar código R directamente
R"library(ggplot2)"
# Pasar datos de Julia a R con $
datos_julia = randn(100)
R"hist($datos_julia, main='Histograma desde Julia', xlab='valores')"
# Llamar funciones R y recoger resultados
media_r = rcopy(R"mean($datos_julia)")
println("Media calculada en R: $media_r")
# Usar un dataframe de R
R"""
df_r <- data.frame(
x = 1:10,
y = rnorm(10)
)
modelo <- lm(y ~ x, data=df_r)
coeficientes <- coef(modelo)
"""
coefs = rcopy(R"coeficientes")
Llamadas a C: ccall
Para llamar a funciones de bibliotecas C dinámicas, Julia tiene ccall sin necesidad de FFI ni wrappers adicionales. La llamada es directa y sin overhead:
# Llamar a funciones de la librería matemática de C
resultado = ccall((:sin, "libm"), Float64, (Float64,), 1.5)
println("sin(1.5) desde libm C: $resultado")
# Llamar a strlen de libc
s = "hola mundo"
longitud = ccall((:strlen, "libc"), Csize_t, (Cstring,), s)
println("Longitud: $longitud")
# Llamar a una función de una librería propia
# suponiendo libmicalculo.so con función double calcular(double x)
# resultado = ccall((:calcular, "libmicalculo"), Float64, (Float64,), 3.14)
# Tipos de C disponibles en Julia
# Cint, Cuint, Clong, Cfloat, Cdouble, Cstring, Ptr{T}, etc.
Llamadas a Fortran
El código Fortran legacy es frecuente en computación científica. ccall funciona también para Fortran, con la convención de que los argumentos se pasan por referencia:
# Fortran pasa todo por referencia (Ref)
# suponiendo una función Fortran: subroutine suma(a, b, resultado)
# ccall((:suma_, "libfortranmod"), Cvoid,
# (Ref{Float64}, Ref{Float64}, Ref{Float64}),
# a, b, resultado)
CxxWrap.jl: interop con C++
Para C++, CxxWrap.jl permite crear wrappers de clases y funciones C++ que se comportan como tipos Julia nativos. Es más complejo de configurar que ccall, pero necesario para librerías C++ con clases y templates.
La estrategia práctica
La interoperabilidad de Julia resuelve el problema del «two-language problem» que afecta a Python: escribes un prototipo en Python, y cuando necesitas rendimiento tienes que reescribirlo en C++ o Cython. Con Julia, el prototipo y el código de producción son el mismo código. Y cuando necesitas una librería Python o R que no existe en Julia, la llamas directamente.
Esta integración es especialmente valiosa si vienes del mundo de Python y quieres empezar a usar Julia gradualmente: puedes llamar a scikit-learn, pandas o matplotlib desde Julia mientras vas aprendiendo las alternativas nativas como DataFrames.jl y Plots.jl.
Imagen: Pexels / Pixabay
