Loading...
Loading...
Guide for migrating OCaml projects, libraries, modules, and test suites to idiomatic MoonBit. Use when translating OCaml code to MoonBit, planning a large OCaml-to-MoonBit port, preserving byte/string-heavy behavior, replacing OCaml variants/records/exceptions/refs/arrays, mapping OCaml APIs to MoonBit packages, or building verification and test strategy for a migration.
npx skill4agent add moonbitlang/skills ocaml2moonbit-migrationstringStringmoon run -c '...'moon 0.1.20260512stringmoon.pkgopenmoon run -cmoon checkmoon testmoon infomoon fmtmoon check --warn-list +...| OCaml use | MoonBit default |
|---|---|
| binary payload, file contents, compressed/encrypted/checksummed data, parser input | |
| human-readable text, diagnostics, labels that are truly Unicode | |
| single byte with known 0..255 range | |
| indexes, counts, small identifiers, deliberate signed 32-bit wrapping | |
| file offsets, serialized positions, large object numbers | |
OCaml | |
| mutable growable builder | |
| read-only sequence parameter | |
| compile-time lookup table (literal or comprehension) | |
| keyed lookup with deterministic iteration | |
OCaml | |
OCaml | |
| OCaml variant | |
| OCaml record | |
| OCaml exception flow | |
| lazy/deferred state | |
OCaml | |
OCaml | |
OCaml | |
Int32String.lengthString::length()ocaml -noprompt -noinit <<'EOF'
let s = "𝄞";;
Printf.printf "%d\n" (String.length s);;
Printf.printf "%d\n" (Char.code s.[0]);;
EOF
# 4
# 240moon run -c 'fn main { let s = "𝄞"; println(s.length()); println(s.char_length()) }'
# 2
# 1String::length()String::char_length()BytesBytesViewBytesString@ascii.encode@utf8.encodemoon run -c 'fn main { let raw : Array[Byte] = [65, 0, 255]; let b = Bytes::from_array(raw); println(b.length()); println(b[2].to_int()) }'
# 3
# 255moon run -c 'fn main { let source : Array[Byte] = [1, 2]; let bytes = Bytes::from_array(source); source[0] = 9; println(bytes[0].to_int()); println(source[0].to_int()) }'
# 1
# 9Bytes::from_arrayBytesBytesBytesView -> BytesArray[Byte]FixedArray[Byte]moon run -c 'fn main { let empty = Bytes::new(0); let zeros = Bytes::new(2); println(empty.length()); println(zeros.length()); println(zeros[0].to_int()) }'
# 0
# 2
# 0Bytes::new(length)Bytes.emptyBytes.make len '\000'Bytes::copyBytesBytes::makei(len, i => src[i])moon run -c $'let cached_filter = b"/Filter"\nfn main { let b = b"PDF"; println(b.length()); println(b[0].to_int()); println(cached_filter.length()); println(cached_filter[0].to_int()) }'
# 3
# 80
# 7
# 47b"..."Bytesb"/Filter"b"PDF"@ascii@ascii.encode(text)String → BytesStringStringmoon run -c $'fn main { let buf = @buffer.new(); buf.write_bytes(b"PDF"); buf.write_byte(10); let bytes = buf.contents(); println(bytes.length()); println(bytes[0].to_int()); println(bytes[3].to_int()) }'
# 4
# 80
# 10@buffer.Buffermoonbitlang/core/buffer@buffer.new()size_hint=Nbuf.write_bytes(b"...")buf.write_byte(n)buf.write_bytes(@ascii.encode(text))buf.write_bytes(view)buf.contents()Array[Byte]Bytes::from_arrayBufferBuffer.tmoon run -c 'fn main { let s = "/UniJIS-UCS2-H"; println(s.has_prefix("/Uni")); println(s.contains("-UCS2-")); println(s.has_suffix("-H")); println(s[1:]); println(s[1:].to_owned()) }'
# true
# true
# true
# UniJIS-UCS2-H
# UniJIS-UCS2-HString::has_prefixhas_suffixcontainss[start:end]BytesViewStringViewStringStrings[start:end].to_owned()moon run -c 'fn has_ab(view : BytesView) -> Bool { match view { [65, 66, ..] => true; _ => false } }
fn main { let bytes : Bytes = [65, 66, 67]; let view = bytes[:2]; println(view.length()); println(view[0].to_int()); println(has_ab(bytes[:])); println(has_ab(view)) }'
# 2
# 65
# true
# trueBytesViewArrayViewBytesView.to_owned()BytesView::to_owned()BytesBytesViewBytesViewBytesBytesViewBytes.to_owned()Bytesbytes[:]moon run -c 'fn main { let data : Bytes = [60, 65, 62, 0, 12, 60, 66, 62]; println(data.length()); println(data[3].to_int()); println(data[4].to_int()); let view = data[5:]; match view { [60, 66, 62] => println("match"); _ => println("miss") } }'
# 8
# 0
# 12
# match012BytesBytesViewmoon run -c 'fn main { let (b, u, u16, i64, u64) : (Byte, UInt, UInt16, Int64, UInt64) = (255, 7, 65535, 42, 42); println(b.to_int()); println(u.to_string()); println(u16.to_int()); println(i64.to_string()); println(u64.to_string()) }'
# 255
# 7
# 65535
# 42
# 42ByteInt16UInt16IntUIntInt64UInt64FloatDoubleInt32IntInt64UInt64int32(65).to_byte()65.to_byte()65.moon run -c 'fn main { let max = 2147483647; println(max + 1); println(1 << 31); println(0xF0 & 0x0F); println(0x80 >> 7); println(0xAA ^ 0xFF) }'
# -2147483648
# -2147483648
# 0
# 1
# 85Int&|^<<>>moon run -c 'fn main { println((-8) >> 1); println(1 << 32); println(1 >> 32); let logical = ((-8).reinterpret_as_uint() >> 1).reinterpret_as_int(); println(logical) }'
# -4
# 1
# 1
# 2147483644Int1 << 32 == 1Int32.shift_right_logical.to_uint().reinterpret_as_uint()moon run -c $'fn main { let parsed : Result[Int, Error] = try? @string.parse_int("2147483648"); println(parsed is Err(_)); let mut value = 0; for digit in [50,49,52,55,52,56,51,54,52,56] { value = value * 10 + digit - 48 }; println(value); let mut wide = 0L; for digit in [50,49,52,55,52,56,51,54,52,56] { wide = wide * 10L + (digit - 48).to_int64() }; println(wide.to_string()) }'
# true
# -2147483648
# 2147483648@string.parse_intIntInt64UInt64Intmoon run -c 'fn main { println(0x8EA2A1A1 < 0); println(0x8EA2A1A1); println(0x7FFFFFFF < 0x8EA2A1A1); println((-1) % 256) }'
# true
# -1901944415
# false
# -1Int0x7FFFFFFFIntUIntreinterpret_as_uintInt64UInt64%(a - b) mod 2560..255ByteByteUInt64UInt64::to_int()moon run -c 'fn rotr64(value : UInt64, bits : Int) -> UInt64 { (value >> bits) | (value << (64 - bits)) }
fn main { let value : UInt64 = 0x0123456789abcdef; let full : UInt64 = UInt64::lnot(0); println(rotr64(value, 8).to_string()); println((full + (1 : UInt64)).to_string()); println(((0x80 : UInt64) >> 7).to_string()) }'
# 17222085231038278605
# 0
# 1UInt64UInt64x : UInt64Intmoon run -c 'fn main { println(Int::lnot(0)); println((0x0F).lnot()); println((!true).to_string()) }'
# -1
# -16
# falseInt::lnot(value)value.lnot()!exprnot xocaml -noprompt -noinit <<'EOF'
print_endline (string_of_float 2.);;
print_endline (string_of_float infinity);;
EOF
# 2.
# inf
moon run -c 'fn main raise { println((2.0).to_string()); println((1.0 / 0.0).to_string()); let tiny : Double = @string.from_str("1e-10"); println(tiny.to_string()) }'
# 2
# Infinity
# 1e-10Double::to_string()string_of_floatPrintf "%.12g"22.Infinity-Infinityinf-infInfinity0floatmoon run -c 'fn main { println(@math.pow(0.5, 2.0)); println((4.0).sqrt()); println((-3.0).abs()); println((5.5).mod(2.0)) }'
# 0.25
# 2
# 3
# 1.5**@math.pow(base, exponent)Doublevalue.sqrt()value.abs()value.mod(other)@mathsincosatan2lnlog10floorceilroundtruncexp@math.sqrt@math.absmoon ide doc @mathenumDebugEqmoon run -c 'enum E { A(Int) } derive(Debug)
fn E::value(self : E) -> Int { match self { A(n) => n } }
fn main { let value = A(7); println(value.value()) }'
# 7moon run -c 'enum E { A(Int); B(Int) } derive(Debug)
fn main { let xs : Array[E] = [E::A(1), E::B(2)]; println(xs.length()) }'
# 2Type::Constructormoon check --warn-list +73moon run -c 'priv enum Section { NoneSection; ActiveSection }
fn choose(flag : Bool) -> Section { if flag { ActiveSection } else { NoneSection } }
fn main { match choose(true) { ActiveSection => println("active"); NoneSection => println("none") } }'
# activemoon run -c 'priv struct S { value : Int }
fn make() -> S { { value: 1 } }
fn main { let s = make(); println(s.value) }'
# 1priv enumpriv structmoon run -c 'struct S { a : Int; b : Int? } derive(Debug, Eq)
fn main { let s = { a: 1, b: None }; let t = { ..s, b: Some(2) }; match t.b { Some(value) => println(value); None => println(0) } }'
# 2{ ..old, field: value }{ old with field = value }moon run -c 'struct S { values : Int } derive(Debug)
fn make(values : Int) -> S? { Some({ values, }) }
fn main { println(make(7).unwrap().values) }'
# 7{ values, }Objectmoon run -c 'fn range_lookup(ranges : ArrayView[(Int, Int, Int)], key : Int) -> Int? { for range in ranges { if key >= range.0 && key <= range.1 { return Some(range.2 + key - range.0) } }; None }
fn main { let ranges = [(0x21, 0x23, 100), (0x30, 0x30, 200)]; println(range_lookup(ranges, 0x22).unwrap()); println(range_lookup(ranges, 0x24) is None) }'
# 101
# trueArrayView(first, last, base)moon run -c $'let table : ReadOnlyArray[Int?] = [for i in 0..<8 => if i == 5 { Some(10) } else { None }]\nfn lookup(i : Int) -> Int? { if i >= 0 && i < table.length() { table[i] } else { None } }\nfn main { println(lookup(5).unwrap()); println(lookup(0) == None); println(lookup(99) == None); println(table.length()) }'
# 10
# true
# true
# 8let table : ReadOnlyArray[T?] = [...]ReadOnlyArray[T]Array[T]ReadOnlyArray[T][for i in 0..<N => entry(i)]makeimoon run -c $'fn first_sorted(xs : ArrayView[Int]) -> Int { let ys = xs.to_owned(); ys.sort(); ys[0] }\nfn main { let r : Ref[Int] = Ref::{ val: 0 }; r.val += 1; println(r.val); let fixed : FixedArray[Int] = [3, 1, 2]; let grow = [4, 2, 3]; println(first_sorted(fixed)); println(first_sorted(grow)); println(fixed[0]); println(grow[0]) }'
# 1
# 1
# 2
# 3
# 4Ref[T]mutArrayFixedArrayarrayArrayView[T]ArrayFixedArray.to_owned()Arraysort()sort_by()enummoon run -c 'fn main { let xs = [(2, "b"), (1, "a")]; xs.sort_by(fn(a, b) { a.0.compare(b.0) }); println(xs[0].0); let ys = [1, 2, 3]; let zs = ys.rev(); println(zs[0]); println(ys[0]) }'
# 1
# 3
# 1Array::sort_byIntArray::rev()List.revmoon run -c $'fn main { let m : Map[Int, String] = Map([]); m[3] = "three"; m[1] = "one"; m[2] = "two"; for k, v in m { println("\\{k}=\\{v}") } }'
# 3=three
# 1=one
# 2=twoMap[K, V]Map([])Map([], capacity=N)Map::new()@hashmap.HashMap[K, V]moonbitlang/core/hashmapNot_foundEnd_of_fileInvalid_argumentmoon run -c $'suberror E\nfn make(flag : Bool) -> ((Int) -> Int?) raise E { if flag { raise E } else { fn(x) { Some(x) } } }\nfn main raise { println(make(false)(3).unwrap()) }'
# 3moon run -c $'fn parse(s : String) -> Int raise { @string.parse_int(s) }\nfn helper() -> Int raise { parse("7") }\ntest "raising test body can propagate" { let value = parse("7"); @test.assert_eq(value, 7) }\nfn main raise { println(helper().to_string()) }'
# 7suberrorraise ProjectErrorraisemainfn main raise { ... }try!testtry!failraisetestraise-> ((A) -> B) raise E-> (A) -> B raise Eraisemoon run -c $'fn may_fail(flag : Bool) -> Unit raise { if flag { fail("boom") } }\nfn main { let result : Result[Unit, Error] = try? may_fail(true); println((result is Err(_)).to_string()) }'
# truemoon run -c $'fn parse(s : String) -> Int raise { @string.parse_int(s) }\nfn main {\n try parse("7") catch {\n _ => println(0)\n } noraise {\n value => println(value)\n }\n}'
# 7try? exprResult[T, Error]try expr catch { ... } noraise { value => ... }try ... with ...expr catch { SpecificError => fallback; error => raise error }catchErr(_)match (try? f()) { Ok(...) => ...; Err(...) => ... }try f() catch { ... } noraise { ... }try?match try? expr { ... }moon run -c 'fn helper(x : Int) -> Int { x + 1 }
fn main { println(helper(1)) }'
# 2mainmoon run -cmoon run -c 'fn[A, B, C] apply_pair(f : (A, B) -> C, a : A, b : B) -> (C, A) { (f(a, b), a) }
fn main { let result = apply_pair(fn(x, y) { x + y }, 2, 3); println(result.0); println(result.1) }'
# 5
# 2fn[A, B, C] name(...)fn name[A, B, C](...)moon run -c 'fn apply_twice(f : (Int) -> Int, value : Int) -> Int { f(f(value)) }
fn main { println(apply_twice(fn(x) { x + 1 }, 40)) }'
# 42(Int) -> Intfn(x) { ... }Refmoon run -c 'fn apply(f : (Int) -> Int raise, x : Int) -> Int raise { f(x) }
fn main raise { println(apply(fn(x) raise { if x == 0 { fail("zero") }; x + 1 }, 1)) }'
# 2raise(Int) -> Int raisefn(x) raise { ... }fnfn(x) raise ProjectError { ... }moon run -c $'fn apply(f : (Int) -> Int raise Error) -> Int raise Error { f(1) }\nfn main { let result : Result[Int, Error] = try? apply(fn(x) raise Error { if x > 0 { fail("x") } else { x } }); println(result is Err(_)) }'
# trueraisemoon run -c $'fn greet(name? : String = "pdf") -> String { name }\nfn main { println(greet()); println(greet(name="moon")) }'
# pdf
# moonname? : T = defaultname=valuemoon run -c 'fn inner(flag? : Bool = false) -> Bool { flag }
fn outer(flag? : Bool = false) -> Bool { inner(flag~) }
fn main { println(outer()); println(outer(flag=true)) }'
# false
# truelabel~moon run -c 'fn takes_view(xs : ArrayView[Int]) -> Int { xs.length() }
fn sample(xs? : ArrayView[Int] = []) -> Int { takes_view(xs) }
fn main { println(sample()); println(sample(xs=[1, 2, 3])) }'
# 0
# 3[]sample(xs=[1, 2, 3])sample([1, 2, 3])moon run -c 'fn f(a : Int, flag? : Bool = true, xs? : ArrayView[Int] = []) -> Int { if flag { a + xs.length() } else { a - xs.length() } }
fn main { println(f(3, xs=[1, 2], flag=false)); println(f(3, flag=true)); println(f(3)) }'
# 1
# 3
# 3Optionx? : T? = Nonelabel~x? : T = default_valueOptionmoon run -c 'enum E { A(Int); B }
fn f(e : E) -> Int { match e { A(n) if n > 0 => n; _ => 0 } }
fn main { println(f(A(3))); println(f(A(-1))); println(f(B)) }'
# 3
# 0
# 0Pattern if condition => ...ifmoon run -c 'fn main { let xs = [1, 2, 3]; match xs { [_, .. rest] => { let owned = [ for x in rest => x ]; println(rest.length()); println(owned.length()); println(owned[0]) }; _ => () } }'
# 2
# 2
# 2.. restArray[T][ for x in rest => x ]moon run -c 'fn main { let fixed : FixedArray[Int] = [1, 2, 3]; let doubled = [ for x in fixed => x * 2 ]; println(doubled.length()); println(doubled[2]) }'
# 3
# 6moon run -c 'fn main { let pairs = [(1, 2), (3, 4)]; let firsts = [ for pair in pairs => pair.0 ]; println(firsts[0]); println(firsts[1]) }'
# 1
# 3[ for x in xs => expr ]moon run -c $'fn parse(s : String) -> Int raise { @string.parse_int(s) }\nfn main { let _ = [ for s in ["1"] => parse(s) ]; println("done") }'
# Error: calling function with error is not allowed inside list comprehension.List.mapArray.mapmoon run -c 'fn main { let m : Map[Int, Int] = Map([]); m[1] = 10; m[2] = 20; let mut total = 0; for key in m.keys() { total += key }; println(total) }'
# 3for x in xsMap@hashmap.HashMapArray.to_array().to_owned()moon run -c 'fn first_positive(xs : Array[Int]) -> Int? { let mut i = 0; while i < xs.length() { if xs[i] > 0 { break Some(xs[i]) }; i += 1 } nobreak { None } }
fn main { println(first_positive([-2, 0, 7]).unwrap()); println(first_positive([-2, 0]) is None) }'
# 7
# truewhilebreak valuenobreak { ... }elseloop ... { ... }aliasundefinedopenmoon.pkg@aliasmoon run -cimport { "moonbitlang/x/crypto" }import "moonbitlang/core/encoding/ascii"@envmoonbitlang/core/envargs() -> Array[String]current_dir() -> String?get_env_var(String) -> String?get_env_vars() -> Map[String, String]now() -> UInt64set_env_varunset_env_varcurrent_dir()x is Some(_).is_some()moon run -c 'fn main { let r = @random.Rand::chacha8(seed=@ascii.encode("01234567890123456789012345678901")); println(r.uint(limit=256).to_string()); println(r.uint(limit=256).to_string()) }'
# 21
# 42@randomRand::new()@random@env.now()moon run --target native -c $'#cfg(target="native")\nfn target_name() -> String { "native" }\n#cfg(not(target="native"))\nfn target_name() -> String { "other" }\nfn main { println(target_name()) }'
# native#cfg(...)#cfgawaitBytesmoonbitlang/asyncBytesmoonbitlang/asyncmoon.pkgmoon run --target native -c 'async fn main { println("async ok") }'
# Error: Cannot use `async fn main`: package moonbitlang/async is not imported.moon run --target native -c $'import {\n "moonbitlang/async",\n "moonbitlang/async/fs" @fs,\n}\nasync fn main {\n let result = try? @fs.read_file("/tmp/definitely-missing-fixture")\n println(result is Err(_))\n}'
# truesupported_targets = "+native"options(targets: { "file_test.mbt": [ "native" ] })*_test.mbt*_wbtest.mbt*.mbt.mdmbt checkmbt nocheck@test.assert_eqDebugShow@test.assert_eq(condition, true)@test.assert_true@test.assert_eqmsg=@test.assert_eqfail-> Unit raise Errorassert_true(value is Pattern(...))guard ... else { fail(...) }inspect(value, content="...")debug_inspect(value, content=...)Debuginspect(value)moon test --updatelet result : Result[T, Error] = try? f()Err(_)moon run -c 'fn helper() -> Unit raise Error { @test.assert_eq(true, true); @test.assert_eq([1, 2], [1, 2]) }
fn main raise { helper() }'moon run -c 'import { "moonbitlang/core/test" }
fn helper() -> Unit raise { @test.assert_eq(true, true, msg="named assertion") }
fn main raise { helper(); println("ok") }'
# okmoon run -c 'fn main { ... }' # quick language/API probe
moon check --warn-list +73 # fast type check with extra warnings
moon test --outline # list discovered tests
moon test # run all tests
moon test path/to/file_test.mbt # run one test file
moon test package/dir --filter 'glob' # targeted test glob
moon test --update # refresh snapshots, then review diff
moon test --target native # required for async I/O tests
moon coverage analyze > uncovered.log # coverage report
moon info && moon fmt # final interface update and formatmoon testmoon check --warn-list +73moon testmoon infomoon fmtmoon run -c