diff --git a/src/lib/card.ts b/src/lib/card.ts
index 79336ed..553596d 100644
--- a/src/lib/card.ts
+++ b/src/lib/card.ts
@@ -19,7 +19,7 @@ export type CardVm = Vm<{
 }>;
 
 export function GetField(vm: CardVm, argv: TextPiece[]): ProcResult {
-  const [{ error }, fieldName] = getOpt(argv, { $min: 1, $max: 1 });
-  if (error) return { error };
-  return { text: vm.card.fields[fieldName] ?? error ?? "" };
+  return getOpt(argv, { $min: 1, $max: 1 }, ({}, fieldName) => ({
+    text: vm.card.fields[fieldName] ?? "",
+  }));
 }
diff --git a/src/lib/options.ts b/src/lib/options.ts
index 7843fc3..30f3aa0 100644
--- a/src/lib/options.ts
+++ b/src/lib/options.ts
@@ -1,4 +1,4 @@
-import { AsText, TextPiece } from "../words";
+import { AsText, ErrorResult, ProcResult, TextPiece } from "../words";
 
 export type Options = Record<string, number> & {
   $min?: number;
@@ -14,20 +14,66 @@ type ParsedOptions<P extends Options> = {
   error?: string;
 };
 
+export function getOpt<P extends Options>(
+  argv: TextPiece[],
+  options: P,
+  procBody: (switches: ParsedOptions<P>, ...argv: string[]) => ProcResult
+): ProcResult;
 export function getOpt<P extends Options>(
   argv: TextPiece[],
   options: P
-): [ParsedOptions<P>, ...string[]] {
-  const [flags, textPieces] = getOptRaw(argv, options);
-  return [flags, ...textPieces.map(AsText)];
+): [ParsedOptions<P>, ...string[]];
+export function getOpt<P extends Options>(
+  argv: TextPiece[],
+  options: P,
+  procBody?: (switches: ParsedOptions<P>, ...argv: string[]) => ProcResult
+): [ParsedOptions<P>, ...string[]] | ProcResult {
+  const [flags, textPieces] = getOptCore(argv, options);
+
+  if (procBody) {
+    if ("error" in flags) {
+      return flags as ErrorResult;
+    } else {
+      return procBody(flags, ...textPieces.map(AsText));
+    }
+  } else {
+    return [flags, ...textPieces.map(AsText)];
+  }
 }
 
 export function getOptRaw<P extends Options>(
+  argv: TextPiece[],
+  options: P,
+  procBody: (switches: ParsedOptions<P>, argv: TextPiece[]) => ProcResult
+): ProcResult;
+export function getOptRaw<P extends Options>(
+  argv: TextPiece[],
+  options: P
+): [ParsedOptions<P>, TextPiece[]];
+export function getOptRaw<P extends Options>(
+  argv: TextPiece[],
+  options: P,
+  procBody?: (switches: ParsedOptions<P>, argv: TextPiece[]) => ProcResult
+): [ParsedOptions<P>, TextPiece[]] | ProcResult {
+  const [flags, textPieces] = getOptCore(argv, options);
+
+  if (procBody) {
+    if ("error" in flags) {
+      return flags as ErrorResult;
+    } else {
+      return procBody(flags, textPieces);
+    }
+  } else {
+    return [flags, textPieces];
+  }
+}
+
+function getOptCore<P extends Options>(
   argv: TextPiece[],
   options: P
 ): [ParsedOptions<P>, TextPiece[]] {
-  const [cmd, ...words] = argv;
-  const result: ParsedOptions<P> = Object.fromEntries(
+  const [cmd, ...textPiece] = argv;
+  const flags: ParsedOptions<P> = Object.fromEntries(
     Object.entries(options)
       .filter(([name]) => name != "$min" && name != "$max")
       .map(([name]) => [])
@@ -35,18 +81,22 @@ export function getOptRaw<P extends Options>(
 
   // TODO: parse switches
 
-  if (options.$min !== undefined && options.$min > words.length) {
+  if (options.$min !== undefined && options.$min > textPiece.length) {
     return [
-      { error: `${AsText(cmd)}: Not enough arguments` } as ParsedOptions<P>,
+      {
+        error: `${AsText(cmd)}: Not enough arguments`,
+      } as ParsedOptions<P>,
       [],
     ];
   }
-  if (options.$max !== undefined && options.$max < words.length) {
+  if (options.$max !== undefined && options.$max < textPiece.length) {
     return [
-      { error: `${AsText(cmd)}: Too many arguments` } as ParsedOptions<P>,
+      {
+        error: `${AsText(cmd)}: Too many arguments`,
+      } as ParsedOptions<P>,
       [],
     ];
   }
 
-  return [result, words];
+  return [flags, textPiece];
 }