#set document(title: "1.1 Mojo quickstart", author: "Modular Inc. / XYZ Homework") #set page(width: 8.5in, height: auto, margin: 1in) #import "@preview/cetz:0.5.2" #set text(font: ("STIX Two Text", "Libertinus Serif", "New Computer Modern"), size: 10.5pt, lang: "en") #show math.equation: set text(font: ("STIX Two Math", "New Computer Modern Math")) #set par(justify: true, leading: 0.62em, spacing: 0.9em) #set enum(spacing: 1.1em) // room between list items so tall inline fractions don't collide #set list(spacing: 1.1em) #set table(stroke: 0.5pt + rgb("#c7ccd3")) #let BLUE = rgb("#183B6F") // brand navy — section bars + example/solution labels (white on navy 11.09:1) #let ORANGE = rgb("#A94509") // brand primary-700 — AA-safe deep orange for TEXT (5.93:1 on white; raw brand #F37021 is 2.94:1 and must never carry text) #let RED = rgb("#DC2626") // brand error-600 #let GREEN = rgb("#059669") // brand success-600 (decoration only; small green text uses green-text #007942) #show heading.where(level: 1): it => block(width: 100%, above: 0pt, below: 16pt, fill: gradient.linear(BLUE, rgb("#2C5AA0")), inset: (x: 14pt, y: 12pt), radius: 3pt, text(fill: white, weight: "bold", size: 19pt, it.body)) #show heading.where(level: 2): it => block(width: 100%, above: 18pt, below: 10pt, fill: BLUE, inset: (x: 10pt, y: 6pt), radius: 2pt, text(fill: white, weight: "bold", size: 12pt, it.body)) #show heading.where(level: 3): it => text(fill: ORANGE, weight: "bold", size: 12.5pt, it.body) #show heading.where(level: 4): it => text(fill: BLUE, weight: "bold", size: 10.5pt, it.body) #let examplebox(label, title, body) = block(width: 100%, breakable: true, fill: rgb("#EFF1F5"), stroke: 0.5pt + rgb("#CFDDF0"), radius: 4pt, inset: 10pt, above: 12pt, below: 12pt)[ #block(below: 6pt)[#box(fill: BLUE, inset: (x: 6pt, y: 2pt), radius: 2pt, text(fill: white, weight: "bold", size: 8.5pt, label)) #h(0.4em) #strong[#title]] #body] // rail = decorative left rule (raw brand token); labelcolor = AA-safe label text shade #let notebox(label, rail, labelcolor, tint, body) = block(width: 100%, breakable: true, fill: tint, stroke: (left: 3pt + rail), inset: (left: 10pt, rest: 8pt), radius: (right: 4pt), above: 11pt, below: 11pt)[ #text(fill: labelcolor, weight: "bold", size: 7.5pt, tracking: 0.5pt)[#upper(label)] #linebreak() #body] #let solutionbox(body) = block(above: 4pt, below: 8pt)[ #text(fill: BLUE, weight: "bold", size: 8.5pt)[Solution] #linebreak() #body] #let figph(msg) = block(width: 100%, height: 60pt, fill: rgb("#f6f7f9"), stroke: (paint: rgb("#c7ccd3"), dash: "dashed"), radius: 4pt, inset: 10pt)[ #align(center + horizon, text(fill: rgb("#889"), style: "italic", size: 9pt, msg))] // Standardize inlined figure sizes: measure the natural CeTZ canvas, then scale to a // consistent envelope (aspect-aware; see build_typst.py FIG_* constants). Unlike the // print preamble, dimensions are FLOORED: in an editor a user can trim a figure to a // degenerate 1-D shape (a bare line), and w/h or tw/w would then divide by zero. #let _STD_W = 3.5 #let _WIDE_W = 5.6 #let _MAX_H = 3.4 #let _ASPECT_WIDE = 2.2 #let _UPSCALE_MAX = 1.15 #let stdfig(body) = context { let m = measure(body) let w = calc.max(m.width / 1in, 0.01) let h = calc.max(m.height / 1in, 0.01) let tw = if w / h > _ASPECT_WIDE { _WIDE_W } else { _STD_W } let s = calc.min(tw / w, _MAX_H / h, _UPSCALE_MAX) align(center, box(scale(x: s * 100%, y: s * 100%, reflow: true, body))) } #show figure: set block(breakable: false) #set figure(gap: 8pt) #show figure.caption: set text(size: 8.5pt, fill: rgb("#555")) == 1.1#h(0.6em)Mojo quickstart This page quickly teaches you Mojo's syntax by focusing on code. For more explanation of the language features, see the Mojo get started tutorial or Mojo language basics. #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[System requirements] You can use Mac, Linux, or Windows with WSL. For details, see the #link("https://mojolang.org/docs/requirements/")[system requirements]. ] === Project setup You can install Mojo using any Python or Conda package manager, but we recommend either pixi or uv. Use the following command to install the : ==== uv + If needed, install uv: curl -LsSf https://astral.sh/uv/install.sh | sh + Create a project and install Mojo: uv init temperature-analyzer && cd temperature-analyzer uv venv && source .venv/bin/activate uv add mojo --prerelease allow Note that the --prerelease allow flag is required only when installing beta (or dev) builds. ==== pixi + If needed, install pixi: curl -fsSL https://pixi.sh/install.sh | sh + Create a project and install Mojo: pixi init temperature-analyzer \\ -c https://conda.modular.com/max/ -c conda-forge cd temperature-analyzer pixi add mojo pixi shell === Hello Mojo Create analyzer.mojo in your favorite IDE or editor. Add this to analyzer.mojo: def main(): print("Temperature Analyzer") Temperature Analyzer Run it: mojo analyzer.mojo Insights: - If you see "Temperature Analyzer", your setup works. - All Mojo executables use main() as their entry point. === Variables and data Update your file to add temperature data: def main(): print("Temperature Analyzer") \# Square brackets tell Mojo the \`List\` type at compile time var temps: List\[Float64\] = \[20.5, 22.3, 19.8, 25.1\] print("Recorded", len(temps), "temperatures") Temperature Analyzer Recorded 4 temperatures === Loops Print each temperature. Add to main() under the print statement: def main(): \# ... existing code ... for index in range(len(temps)): \# The range is \[0, len(temps)) print(t" Day {index + 1}: {temps\[index\]}°C") Insights: - The day is offset by 1 because the range uses zero-based indexing. - The t"..." prefix creates a #emph[template string]: braces {} interpolate expressions directly into the output. This is useful because it avoids memory allocations for the intermediate values. === Functions Add this function above main() to calculate the average temperature: def calculate\_average(temps: List\[Float64\]) -\> Float64: var total: Float64 = 0.0 for index in range(len(temps)): total += temps\[index\] return total / Float64(len(temps)) def main(): \# ... existing code ... Add to the end of main() to call the function: var avg = calculate\_average(temps) print(t"Average: {avg}°C") === Conditionals Classify the average temperature. Add to the end of main(): if avg \> 25.0: print("Status: Hot week") elif avg \> 20.0: print("Status: Comfortable week") else: print("Status: Cool week") === Raise errors Handle empty data by updating calculate\_average. Now the function can raise an error. def calculate\_average(temps: List\[Float64\]) raises -\> Float64: if len(temps) == 0: \# Empty list of temperatures raise Error("No temperature data") var total: Float64 = 0.0 for index in range(len(temps)): total += temps\[index\] return total / Float64(len(temps)) What changed: - You add raises before the return arrow. - You add the check for an empty list. - You raise an Error if it's empty. === Handle errors In main(), wrap your code in try-except for error handling: try: var avg = calculate\_average(temps) print(t"Average: {avg}°C") if avg \> 25.0: print("Status: Hot week") elif avg \> 20.0: print("Status: Comfortable week") else: print("Status: Cool week") except e: print("Error:", e) To test the error, replace temps with List\[Float64\](). Confirm that your app errors with "No temperature data". === Python integration Add statistics with Python's numpy. First, install it: ==== uv uv pip install numpy ==== pixi pixi add numpy ==== pip pip install numpy ==== conda conda install numpy Then, add the following imports at the top of your file: from std.python import Python, PythonObject Now, calculate Python stats at the end of the try block in main(): var np = Python.import\_module("numpy") var pytemps: PythonObject = \[20.5, 22.3, 19.8, 25.1\] print("Temperature standard deviation:", np.std(pytemps)) === Final code Your complete analyzer.mojo: from std.python import Python, PythonObject def calculate\_average(temps: List\[Float64\]) raises -\> Float64: if len(temps) == 0: raise Error("No temperature data") var total: Float64 = 0.0 for index in range(len(temps)): total += temps\[index\] return total / Float64(len(temps)) def main(): print("Temperature Analyzer") var temps: List\[Float64\] = \[20.5, 22.3, 19.8, 25.1\] print("Recorded", len(temps), "temperatures") for index in range(len(temps)): print(t" Day {index + 1}: {temps\[index\]}°C") try: var avg = calculate\_average(temps) print(t"Average: {avg}°C") if avg \> 25.0: print("Status: Hot week") elif avg \> 20.0: print("Status: Comfortable week") else: print("Status: Cool week") var np = Python.import\_module("numpy") var pytemps: PythonObject = \[20.5, 22.3, 19.8, 25.1\] print("Temperature standard deviation:", np.std(pytemps)) \_ = pytemps^ \# Allow the Python object to deallocate except e: print("Error:", e) Temperature Analyzer Recorded 4 temperatures Day 1: 20.5°C Day 2: 22.3°C Day 3: 19.8°C Day 4: 25.1°C Average: 21.924999999999997°C Status: Comfortable week Error: No module named 'numpy' === What you touched Mojo variables, lists, loops, functions, conditionals, error handling, and Python integration, all in one working program. === Use Mojo with AI coding assistants If you use AI coding assistants, the mojo-syntax skill keeps you aligned with the latest nightly language releases. Stay up to date with Mojo's rapid development: npx skills add modular/skills This installs all four #link("https://mojolang.org/docs/tools/skills")[Mojo agent skills], including mojo-syntax. === Keep going #strong[Build something bigger:] Tutorial: Game of Life #strong[Language guide:] #link("https://mojolang.org/docs/manual")[Mojo Manual] #strong[API docs:] #link("https://mojolang.org/docs/std")[Standard Library]