packages feed

shikumi-compile-0.1.0.0: src/Shikumi/Compile/Serialize.hs

-- | Serialization of a 'CompiledProgram'.
--
-- __Parameter-state, not whole-structure.__ A @Program@'s structure cannot be
-- serialized in general (its @FMap@ nodes hold opaque functions and its GADT type
-- indices are not reflected at runtime). What /can/ be saved — and is exactly what
-- the optimizer (EP-10) and CLI (EP-12) need — is each node's tunable
-- 'Shikumi.Program.Params', against a known program /template/. This mirrors DSPy's
-- @dump_state@/@load_state@: dump the parameters, load them back onto a program you
-- still hold as code.
--
-- This reuses EP-4's already-provided parameter interface verbatim:
-- 'Shikumi.Program.programParams' (the ordered @[Params]@ vector, in @foldParams@
-- order) and 'Shikumi.Program.setProgramParams' (re-apply a vector onto a matching
-- program, with a length-mismatch guard). So this module is a thin JSON wrapper —
-- the node-order contract and the count check are EP-4's, not re-invented here.
module Shikumi.Compile.Serialize
  ( encodeCompiled,
    decodeCompiledOnto,
  )
where

import Data.Aeson (eitherDecode, encode)
import Data.ByteString.Lazy (ByteString)
import Shikumi.Compile.Types (CompiledProgram (..))
import Shikumi.Program
  ( Params,
    Program,
    ProgramShapeError (..),
    programParams,
    setProgramParams,
  )

-- | Emit a compiled program's ordered parameter vector as JSON (a JSON array of
-- @Params@, in 'Shikumi.Program.foldParams' order).
encodeCompiled :: CompiledProgram i o -> ByteString
encodeCompiled (CompiledProgram p) = encode (programParams p)

-- | Re-apply a saved parameter vector onto a structural /template/ (the base
-- program, held as code), in node order. Fails with a descriptive message if the
-- JSON is malformed or if its node count does not match the template — which would
-- mean the template is not the program the parameters were saved from. The signature
-- mirrors DSPy's @load_state(program)@.
decodeCompiledOnto ::
  Program i o ->
  ByteString ->
  Either String (CompiledProgram i o)
decodeCompiledOnto template bs = do
  ps <- eitherDecode bs :: Either String [Params]
  case setProgramParams ps template of
    Left (ParamCountMismatch (expected, got)) ->
      Left
        ( "shikumi-compile: parameter count mismatch — the template has "
            <> show expected
            <> " node(s) but the saved state has "
            <> show got
        )
    Right prog -> Right (CompiledProgram prog)