#For Haskell and OCaml Readers

This is a delta sheet, not a second tutorial. It lists the places where Haskell or OCaml habits will mislead you in Medaka. For everything else, the main guide applies.

#The delta

Topic In Medaka Reference
Typeclasses A typeclass is an interface; an instance is an impl. requires on an interface declares a superclass. requires on an impl declares the impl's context. Interfaces
Overlapping instances Allowed. When several impls apply, the unique most-specific one is chosen automatically. Genuine ambiguity is an error. There are no named instances, no OVERLAPPING pragmas, and no use-site hints. Selection semantics
Functor / Monad The interfaces are Mappable, Applicative, Thenable, Filterable, and Traversable. The methods are map, pure, and andThen (>>= with the arguments swapped). There is no Functor or Monad, and no IO instance of anything. Interfaces
Default methods A default body lives in the interface, and its signature must mention the interface parameter so dispatch has something to key on. Interfaces
Effects Effects go on the result arrow: String -> <IO> String. A higher-order function can take an effectful argument, a -> <e> b, and <IO | e> is an open row. Signatures
IO and do IO is a plain indented block of statements. do is sugar for Thenable's andThen and pure, and <- is legal only inside it. do notation
Mutation Bindings are immutable. Mutable state is a Ref a: build with Ref value, write with :=, read with prefix !. ! is dereference, not negation; negation is not. Refs
Records No record keyword. A record is a single-constructor data with named fields: data Person = { name : String }. Field names are scoped to their type. Records
Local recursion let rec binds one recursive definition. There is no and for mutually recursive local definitions; top-level definitions are mutually recursive without a keyword. let
Strings String is not a list of characters. string.toChars converts when you need one. Working with Data
Layout Indentation-based, as in Haskell, but a deeper-indented line can continue an expression rather than open a block, depending on the tokens at the boundary. Layout notes
deriving placement Inline after a one-line data declaration. On its own line only when the declaration spans several lines. Data types
Lambdas x y => body, with no backslash. Multi-parameter lambdas are not curried one arrow at a time. (x, y) => … takes a tuple. Lambdas
Backtick infix Removed. Write f x y. Removed

#One checked example

The general impl applies to every type, but the Int impl is the unique most-specific match, so it wins. The same block then writes and reads a Ref before printing:

interface GuideKind a where
  guideKind : a -> String

impl GuideKind a where
  guideKind _ = "general"

impl GuideKind Int where
  guideKind _ = "specific"

main =
  let count = Ref 1
  count := !count + 1
  println (guideKind (1 : Int))
  println !count
specific
2

#Quick checks when something feels wrong

  • If your instinct says "put the IO in do", ask whether you are binding a Thenable value with <-. If not, it belongs in a plain block.
  • If your instinct says let rec … and …, split it into separate definitions, or move them to the top level.
  • If instance selection seems to need a name or a pragma, remove it. Write the more specific impl and let selection pick it.
  • If a name you can see is reported as unbound, check indentation before anything else.