Code Interoperability Guide
View SourceThis guide explains how to use Nasty's bidirectional conversion between natural language and code.
Overview
Nasty provides two-way interoperability:
- NL → Code: Convert natural language descriptions to executable code
- Code → NL: Generate natural language explanations from code
Currently supported: English ↔ Elixir
Natural Language to Code
Basic Usage
# Simple operations
Nasty.to_code("Sort the list",
source_language: :en,
target_language: :elixir)
# => {:ok, "Enum.sort(list)"}
# Filtering
Nasty.to_code("Filter users where age is greater than 18",
source_language: :en,
target_language: :elixir)
# => {:ok, "Enum.filter(users, fn item -> item > 18 end)"}
# Mapping
Nasty.to_code("Map numbers to double each",
source_language: :en,
target_language: :elixir)
# => {:ok, "Enum.map(numbers, fn item -> item * 2 end)"}Supported Patterns
List Operations
Sorting:
"Sort the list" → "Enum.sort(list)"
"Sort numbers" → "Enum.sort(numbers)"Filtering:
"Filter X where Y > Z" → "Enum.filter(x, fn item -> item > z end)"
"Filter X where Y < Z" → "Enum.filter(x, fn item -> item < z end)"
"Filter X where Y == Z" → "Enum.filter(x, fn item -> item == z end)"Multiple constraints (AND logic):
"Filter users where age > 18 and score > 50"
→ "Enum.filter(users, fn item -> item > 18 and item > 50 end)"Mapping:
"Map X" → "Enum.map(x, fn item -> item end)"
"Map X to uppercase" → "Enum.map(x, fn item -> String.upcase(item) end)"Reducing:
"Sum numbers" → "Enum.sum(numbers)"
"Count items" → "Enum.count(items)"Arithmetic Operations
"Add X and Y" → "x + y"
"X plus Y" → "x + y"
"Subtract Y from X" → "x - y"
"Multiply X by Y" → "x * y"
"Divide X by Y" → "x / y"Assignments
"X is 5" → "x = 5"
"Set X to Y" → "x = y"
"Let result equal sum" → "result = sum"Conditionals
"If X then Y" → "if x, do: y"
"If X > 5 then ok" → "if x > 5, do: :ok"Pipeline Architecture
The NL → Code pipeline:
flowchart TD
A[Natural Language Text]
B["Parse to AST (Nasty.parse)"]
C["Intent Recognition (Nasty.Interop.IntentRecognizer)"]
C1["- Analyze sentence structure<br/>- Extract action (sort, filter, map, etc.)<br/>- Identify target (list, users, etc.)<br/>- Extract arguments<br/>- Identify constraints"]
D["Intent AST (%Nasty.AST.Intent{})"]
E["Code Generation (Nasty.Interop.CodeGen.Elixir)"]
E1["- Match intent pattern<br/>- Build Elixir AST using quote<br/>- Generate function calls<br/>- Handle constraints"]
F["Validation (Code.string_to_quoted)"]
G[Elixir Code String]
A --> B
B --> C
C -.-> C1
C --> D
D --> E
E -.-> E1
E --> F
F --> GIntent Structure
Intents are intermediate representations:
%Nasty.AST.Intent{
type: :action, # :action, :query, :definition, :conditional
action: "filter", # Action verb
target: "users", # Target variable/collection
arguments: [], # Additional arguments
constraints: [ # Filtering/conditional constraints
{:comparison, :greater_than, 18}
],
metadata: %{}
}Intent types:
:action- Perform operation (sort, filter, map):query- Ask question (is X equal to Y?):definition- Define/assign (X is Y):conditional- Conditional logic (if X then Y)
Advanced Examples
Complex filtering:
# Multiple AND constraints
Nasty.to_code(
"Filter employees where salary greater than 50000 and age less than 40",
source_language: :en,
target_language: :elixir
)
# => "Enum.filter(employees, fn item -> item > 50000 and item < 40 end)"Nested operations (future):
"Filter users then sort by age"
→ "users |> Enum.filter(...) |> Enum.sort_by(&(&1.age))"Code to Natural Language
Basic Usage
# Simple function calls
Nasty.explain_code("Enum.sort(list)",
source_language: :elixir,
target_language: :en)
# => {:ok, "Sort list"}
# Pipelines
Nasty.explain_code("list |> Enum.map(&(&1 * 2)) |> Enum.sum()",
source_language: :elixir,
target_language: :en)
# => {:ok, "Map list to double each element, then sum the results"}
# Assignments
Nasty.explain_code("x = 5",
source_language: :elixir,
target_language: :en)
# => {:ok, "X is 5"}Supported Patterns
Enum Operations
"Enum.sort(x)" → "Sort X"
"Enum.filter(x, fn i -> i > 5 end)" → "Filter X where item is greater than 5"
"Enum.map(x, fn i -> i * 2 end)" → "Map X to double each element"
"Enum.sum(x)" → "Sum X"
"Enum.count(x)" → "Count X"
"Enum.find(x, fn i -> i == 5 end)" → "Find item in X where item equals 5"Pipelines
"a |> b" → "A, then B"
"list |> Enum.sort() |> Enum.reverse()" → "List, then sort, then reverse"Arithmetic
"x + y" → "X plus Y"
"x - y" → "X minus Y"
"x * y" → "X times Y"
"x / y" → "X divided by Y"Assignments
"x = 5" → "X is 5"
"result = x + y" → "Result equals X plus Y"Conditionals
"if x, do: y" → "If X, return Y"
"if x > 5, do: :ok, else: :error" → "If X is greater than 5, return ok, otherwise error"Pipeline Architecture
The Code → NL pipeline:
flowchart TD
A[Elixir Code String]
B["Parse to Elixir AST (Code.string_to_quoted)"]
C["Traverse AST (Nasty.Interop.CodeGen.Explain)"]
C1["- Match AST patterns<br/>- Recognize Enum calls<br/>- Identify operators<br/>- Handle pipelines<br/>- Extract variables"]
D[Natural Language Fragments]
E[Combine & Format]
F[Natural Language Text]
A --> B
B --> C
C -.-> C1
C --> D
D --> E
E --> FExplanation Styles
Two styles supported via :style option:
Concise (default):
Nasty.explain_code("Enum.sort(list)", style: :concise)
# => "Sort list"Verbose:
Nasty.explain_code("Enum.sort(list)", style: :verbose)
# => "Sort the list in ascending order"Use Cases
1. Code Documentation
Generate documentation from code:
defmodule MyModule do
def process(data) do
data
|> Enum.filter(&(&1.active))
|> Enum.sort_by(&(&1.priority))
|> Enum.map(&transform/1)
end
end
# Generate doc
{:ok, explanation} = Nasty.explain_code(
get_function_body(:process),
source_language: :elixir,
target_language: :en
)
# => "Filter data where active, then sort by priority, then map to transform"2. Natural Language Queries
Allow users to query data using natural language:
defmodule DataQuery do
def query(collection, nl_query) do
case Nasty.to_code(nl_query,
source_language: :en,
target_language: :elixir) do
{:ok, code_string} ->
# Safely evaluate with collection
safe_eval(code_string, collection: collection)
{:error, reason} ->
{:error, reason}
end
end
end
# Usage
DataQuery.query(users, "Filter users where age greater than 25")3. Interactive Learning
Explain code to learners:
defmodule CodeTutor do
def explain_to_learner(code) do
{:ok, explanation} = Nasty.explain_code(code,
source_language: :elixir,
target_language: :en,
style: :verbose
)
IO.puts("This code: #{explanation}")
end
end4. Code Generation from Specs
Generate code from natural language specifications:
specs = [
"Filter products where price less than 100",
"Sort by name",
"Map to uppercase"
]
pipeline = Enum.map_join(specs, " |> ", fn spec ->
{:ok, code} = Nasty.to_code(spec,
source_language: :en,
target_language: :elixir)
code
end)
# => "Enum.filter(products, fn item -> item < 100 end) |>
# Enum.sort_by(&(&1.name)) |>
# Enum.map(fn item -> String.upcase(item) end)"Limitations
Current Limitations
- Single language pair: Only EN ↔ Elixir supported
- Limited patterns: Not all Elixir constructs supported
- Simple constraints: Complex boolean logic not fully supported
- No type inference: Cannot infer types from context
- Limited variable scope: Doesn't track variable definitions
- No side effects: Cannot handle IO, state mutations, etc.
Future Enhancements
- More language pairs: EN ↔ JavaScript, EN ↔ Python
- Advanced patterns: Pattern matching, guards, comprehensions
- Context awareness: Track variable types and scope
- Bidirectional pipelines: Full round-trip NL ↔ Code ↔ NL
- Code understanding: Infer intent from existing code
- Multi-statement programs: Handle complete modules/functions
API Reference
Nasty.to_code/2
Convert natural language to code.
@spec to_code(String.t(), keyword()) :: {:ok, String.t()} | {:error, term()}Options:
:source_language(required) - Natural language (:en):target_language(required) - Programming language (:elixir)
Returns:
{:ok, code_string}- Generated code{:error, reason}- Error
Nasty.explain_code/2
Convert code to natural language.
@spec explain_code(String.t() | Macro.t(), keyword()) :: {:ok, String.t()} | {:error, term()}Options:
:source_language(required) - Programming language (:elixir):target_language(required) - Natural language (:en):style- Explanation style (:conciseor:verbose)
Returns:
{:ok, explanation}- Natural language explanation{:error, reason}- Error
Implementation Details
Intent Recognition
Located in lib/interop/intent_recognizer.ex:
defmodule Nasty.Interop.IntentRecognizer do
@doc """
Recognizes intent from parsed NL AST.
"""
def recognize(%Document{} = doc) do
# Extract clauses, identify action verbs
# Build Intent struct
end
endCode Generation
Located in lib/interop/code_gen/elixir.ex:
defmodule Nasty.Interop.CodeGen.Elixir do
@doc """
Generates Elixir AST from Intent.
"""
def generate(%Intent{} = intent) do
# Pattern match on intent type
# Use quote to build Elixir AST
# Validate and return
end
endCode Explanation
Located in lib/interop/code_gen/explain.ex:
defmodule Nasty.Interop.CodeGen.Explain do
@doc """
Explains Elixir code in natural language.
"""
def explain_code(code_string) do
# Parse to Elixir AST
# Traverse and explain patterns
# Generate NL text
end
end