kripke: add prettyPrint

This commit is contained in:
2025-02-18 04:52:51 +09:00
parent 3a4983aa67
commit 6d262460f2

View File

@@ -51,3 +51,101 @@ export const or = (left: Formula, right: Formula) =>
({ type: "or", left, right }) as const satisfies Formula;
export const iff = (left: Formula, right: Formula) =>
({ type: "iff", left, right }) as const satisfies Formula;
export type Symbols = Record<Exclude<Formula["type"], "propvar">, string>;
export const asciiSymbols: Symbols = {
top: "T",
bot: "F",
box: "[]",
diamond: "<>",
not: "~",
and: "^",
or: "v",
to: "->",
iff: "<->",
};
export const unicodeSymbols: Symbols = {
top: "",
bot: "⊥",
box: "□",
diamond: "⋄",
not: "¬",
and: "∧",
or: "",
to: "→",
iff: "↔",
};
export const latexSymbols: Symbols = {
top: "\\top",
bot: "\\bot",
box: "\\Box",
diamond: "\\Diamond",
not: "\\neg",
and: "\\land",
or: "\\lor",
to: "\\to",
iff: "\\leftrightarrow",
};
export function prettyPrint(
fml: Formula,
config?: { paren?: boolean | ((fml: Formula) => boolean); symbols?: Symbols },
): string {
const { paren = false, symbols = unicodeSymbols } = config ?? {};
const withParen = (s: string) =>
(typeof paren === "boolean" ? paren : paren(fml)) ? `(${s})` : s;
switch (fml.type) {
case "top":
return symbols.top;
case "bot":
return symbols.bot;
case "propvar":
return fml.name;
case "not":
return `${symbols.not}${prettyPrint(fml.fml, { paren: true, symbols })}`;
case "box":
return `${symbols.box}${prettyPrint(fml.fml, { paren: true, symbols })}`;
case "diamond":
return `${symbols.diamond}${prettyPrint(fml.fml, { paren: true, symbols })}`;
case "and": {
const newConfig: typeof config = {
symbols,
paren: (f) => f.type !== "and",
};
return withParen(
`${prettyPrint(fml.left, newConfig)} ${symbols.and} ${prettyPrint(fml.right, newConfig)}`,
);
}
case "or": {
const newConfig: typeof config = {
symbols,
paren: (f) => f.type !== "or",
};
return withParen(
`${prettyPrint(fml.left, newConfig)} ${symbols.or} ${prettyPrint(fml.right, newConfig)}`,
);
}
case "to": {
const newConfig: typeof config = {
symbols,
paren: (f) => f.type !== "to",
};
return withParen(
`${prettyPrint(fml.left, { symbols, paren: true })} ${symbols.to} ${prettyPrint(fml.right, newConfig)}`,
);
}
case "iff": {
const newConfig: typeof config = {
symbols,
paren: (f) => f.type !== "iff",
};
return withParen(
`${prettyPrint(fml.left, newConfig)} ${symbols.iff} ${prettyPrint(fml.right, newConfig)}`,
);
}
}
}