mcard-js 2.1.12 → 2.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/hash/HashValidator.d.ts +14 -0
- package/dist/hash/HashValidator.d.ts.map +1 -0
- package/dist/hash/HashValidator.js +57 -0
- package/dist/hash/HashValidator.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/model/CardCollection.d.ts +92 -0
- package/dist/model/CardCollection.d.ts.map +1 -0
- package/dist/model/CardCollection.js +217 -0
- package/dist/model/CardCollection.js.map +1 -0
- package/dist/model/ContentTypeInterpreter.d.ts +23 -0
- package/dist/model/ContentTypeInterpreter.d.ts.map +1 -0
- package/dist/model/ContentTypeInterpreter.js +140 -0
- package/dist/model/ContentTypeInterpreter.js.map +1 -0
- package/dist/model/EventProducer.d.ts +10 -0
- package/dist/model/EventProducer.d.ts.map +1 -0
- package/dist/model/EventProducer.js +46 -0
- package/dist/model/EventProducer.js.map +1 -0
- package/dist/model/GTime.d.ts +44 -0
- package/dist/model/GTime.d.ts.map +1 -0
- package/dist/model/GTime.js +91 -0
- package/dist/model/GTime.js.map +1 -0
- package/dist/model/Handle.d.ts +37 -0
- package/dist/model/Handle.d.ts.map +1 -0
- package/dist/model/Handle.js +90 -0
- package/dist/model/Handle.js.map +1 -0
- package/dist/model/MCard.d.ts +43 -0
- package/dist/model/MCard.d.ts.map +1 -0
- package/dist/model/MCard.js +76 -0
- package/dist/model/MCard.js.map +1 -0
- package/dist/model/constants.d.ts +45 -0
- package/dist/model/constants.d.ts.map +1 -0
- package/dist/model/constants.js +27 -0
- package/dist/model/constants.js.map +1 -0
- package/dist/model/detectors/BaseDetector.d.ts +26 -0
- package/dist/model/detectors/BaseDetector.d.ts.map +1 -0
- package/dist/model/detectors/BaseDetector.js +5 -0
- package/dist/model/detectors/BaseDetector.js.map +1 -0
- package/dist/model/detectors/BinaryDetector.d.ts +12 -0
- package/dist/model/detectors/BinaryDetector.d.ts.map +1 -0
- package/dist/model/detectors/BinaryDetector.js +82 -0
- package/dist/model/detectors/BinaryDetector.js.map +1 -0
- package/dist/model/detectors/ContentTypeInterpreter.d.ts +11 -0
- package/dist/model/detectors/ContentTypeInterpreter.d.ts.map +1 -0
- package/dist/model/detectors/ContentTypeInterpreter.js +51 -0
- package/dist/model/detectors/ContentTypeInterpreter.js.map +1 -0
- package/dist/model/detectors/DataFormatDetectors.d.ts +29 -0
- package/dist/model/detectors/DataFormatDetectors.d.ts.map +1 -0
- package/dist/model/detectors/DataFormatDetectors.js +223 -0
- package/dist/model/detectors/DataFormatDetectors.js.map +1 -0
- package/dist/model/detectors/LanguageDetector.d.ts +11 -0
- package/dist/model/detectors/LanguageDetector.d.ts.map +1 -0
- package/dist/model/detectors/LanguageDetector.js +148 -0
- package/dist/model/detectors/LanguageDetector.js.map +1 -0
- package/dist/model/detectors/MarkupDetectors.d.ts +22 -0
- package/dist/model/detectors/MarkupDetectors.d.ts.map +1 -0
- package/dist/model/detectors/MarkupDetectors.js +132 -0
- package/dist/model/detectors/MarkupDetectors.js.map +1 -0
- package/dist/model/detectors/OBJDetector.d.ts +8 -0
- package/dist/model/detectors/OBJDetector.d.ts.map +1 -0
- package/dist/model/detectors/OBJDetector.js +48 -0
- package/dist/model/detectors/OBJDetector.js.map +1 -0
- package/dist/model/detectors/registry.d.ts +13 -0
- package/dist/model/detectors/registry.d.ts.map +1 -0
- package/dist/model/detectors/registry.js +67 -0
- package/dist/model/detectors/registry.js.map +1 -0
- package/dist/monads/Either.d.ts +51 -0
- package/dist/monads/Either.d.ts.map +1 -0
- package/dist/monads/Either.js +82 -0
- package/dist/monads/Either.js.map +1 -0
- package/dist/monads/IO.d.ts +38 -0
- package/dist/monads/IO.d.ts.map +1 -0
- package/dist/monads/IO.js +66 -0
- package/dist/monads/IO.js.map +1 -0
- package/dist/monads/Maybe.d.ts +45 -0
- package/dist/monads/Maybe.d.ts.map +1 -0
- package/dist/monads/Maybe.js +73 -0
- package/dist/monads/Maybe.js.map +1 -0
- package/dist/monads/Reader.d.ts +29 -0
- package/dist/monads/Reader.d.ts.map +1 -0
- package/dist/monads/Reader.js +44 -0
- package/dist/monads/Reader.js.map +1 -0
- package/dist/monads/State.d.ts +33 -0
- package/dist/monads/State.d.ts.map +1 -0
- package/dist/monads/State.js +50 -0
- package/dist/monads/State.js.map +1 -0
- package/dist/monads/Writer.d.ts +29 -0
- package/dist/monads/Writer.d.ts.map +1 -0
- package/dist/monads/Writer.js +46 -0
- package/dist/monads/Writer.js.map +1 -0
- package/dist/ptr/FaroSidecar.d.ts +56 -0
- package/dist/ptr/FaroSidecar.d.ts.map +1 -0
- package/dist/ptr/FaroSidecar.js +102 -0
- package/dist/ptr/FaroSidecar.js.map +1 -0
- package/dist/ptr/LensProtocol.d.ts +84 -0
- package/dist/ptr/LensProtocol.d.ts.map +1 -0
- package/dist/ptr/LensProtocol.js +98 -0
- package/dist/ptr/LensProtocol.js.map +1 -0
- package/dist/ptr/SandboxWorker.d.ts +54 -0
- package/dist/ptr/SandboxWorker.d.ts.map +1 -0
- package/dist/ptr/SandboxWorker.js +172 -0
- package/dist/ptr/SandboxWorker.js.map +1 -0
- package/dist/ptr/common_types.d.ts +39 -0
- package/dist/ptr/common_types.d.ts.map +1 -0
- package/dist/ptr/common_types.js +12 -0
- package/dist/ptr/common_types.js.map +1 -0
- package/dist/ptr/lambda/AlphaConversion.d.ts +42 -0
- package/dist/ptr/lambda/AlphaConversion.d.ts.map +1 -0
- package/dist/ptr/lambda/AlphaConversion.js +244 -0
- package/dist/ptr/lambda/AlphaConversion.js.map +1 -0
- package/dist/ptr/lambda/BetaReduction.d.ts +73 -0
- package/dist/ptr/lambda/BetaReduction.d.ts.map +1 -0
- package/dist/ptr/lambda/BetaReduction.js +322 -0
- package/dist/ptr/lambda/BetaReduction.js.map +1 -0
- package/dist/ptr/lambda/EtaConversion.d.ts +65 -0
- package/dist/ptr/lambda/EtaConversion.d.ts.map +1 -0
- package/dist/ptr/lambda/EtaConversion.js +228 -0
- package/dist/ptr/lambda/EtaConversion.js.map +1 -0
- package/dist/ptr/lambda/FreeVariables.d.ts +44 -0
- package/dist/ptr/lambda/FreeVariables.d.ts.map +1 -0
- package/dist/ptr/lambda/FreeVariables.js +207 -0
- package/dist/ptr/lambda/FreeVariables.js.map +1 -0
- package/dist/ptr/lambda/LambdaRuntime.d.ts +80 -0
- package/dist/ptr/lambda/LambdaRuntime.d.ts.map +1 -0
- package/dist/ptr/lambda/LambdaRuntime.js +433 -0
- package/dist/ptr/lambda/LambdaRuntime.js.map +1 -0
- package/dist/ptr/lambda/LambdaTerm.d.ts +95 -0
- package/dist/ptr/lambda/LambdaTerm.d.ts.map +1 -0
- package/dist/ptr/lambda/LambdaTerm.js +159 -0
- package/dist/ptr/lambda/LambdaTerm.js.map +1 -0
- package/dist/ptr/lambda/index.d.ts +24 -0
- package/dist/ptr/lambda/index.d.ts.map +1 -0
- package/dist/ptr/lambda/index.js +34 -0
- package/dist/ptr/lambda/index.js.map +1 -0
- package/dist/ptr/llm/Config.d.ts +57 -0
- package/dist/ptr/llm/Config.d.ts.map +1 -0
- package/dist/ptr/llm/Config.js +183 -0
- package/dist/ptr/llm/Config.js.map +1 -0
- package/dist/ptr/llm/LLMRuntime.d.ts +35 -0
- package/dist/ptr/llm/LLMRuntime.d.ts.map +1 -0
- package/dist/ptr/llm/LLMRuntime.js +176 -0
- package/dist/ptr/llm/LLMRuntime.js.map +1 -0
- package/dist/ptr/llm/providers/LLMProvider.d.ts +43 -0
- package/dist/ptr/llm/providers/LLMProvider.d.ts.map +1 -0
- package/dist/ptr/llm/providers/LLMProvider.js +31 -0
- package/dist/ptr/llm/providers/LLMProvider.js.map +1 -0
- package/dist/ptr/llm/providers/MLCLLMProvider.d.ts +22 -0
- package/dist/ptr/llm/providers/MLCLLMProvider.d.ts.map +1 -0
- package/dist/ptr/llm/providers/MLCLLMProvider.js +155 -0
- package/dist/ptr/llm/providers/MLCLLMProvider.js.map +1 -0
- package/dist/ptr/llm/providers/OllamaEmbeddingProvider.d.ts +20 -0
- package/dist/ptr/llm/providers/OllamaEmbeddingProvider.d.ts.map +1 -0
- package/dist/ptr/llm/providers/OllamaEmbeddingProvider.js +42 -0
- package/dist/ptr/llm/providers/OllamaEmbeddingProvider.js.map +1 -0
- package/dist/ptr/llm/providers/OllamaProvider.d.ts +21 -0
- package/dist/ptr/llm/providers/OllamaProvider.d.ts.map +1 -0
- package/dist/ptr/llm/providers/OllamaProvider.js +158 -0
- package/dist/ptr/llm/providers/OllamaProvider.js.map +1 -0
- package/dist/ptr/llm/providers/WebLLMProvider.d.ts +22 -0
- package/dist/ptr/llm/providers/WebLLMProvider.d.ts.map +1 -0
- package/dist/ptr/llm/providers/WebLLMProvider.js +151 -0
- package/dist/ptr/llm/providers/WebLLMProvider.js.map +1 -0
- package/dist/ptr/node/Action.d.ts +426 -0
- package/dist/ptr/node/Action.d.ts.map +1 -0
- package/dist/ptr/node/Action.js +711 -0
- package/dist/ptr/node/Action.js.map +1 -0
- package/dist/ptr/node/CLMLoader.d.ts +18 -0
- package/dist/ptr/node/CLMLoader.d.ts.map +1 -0
- package/dist/ptr/node/CLMLoader.js +18 -0
- package/dist/ptr/node/CLMLoader.js.map +1 -0
- package/dist/ptr/node/CLMRunner.d.ts +34 -0
- package/dist/ptr/node/CLMRunner.d.ts.map +1 -0
- package/dist/ptr/node/CLMRunner.js +36 -0
- package/dist/ptr/node/CLMRunner.js.map +1 -0
- package/dist/ptr/node/FileSystemUtils.d.ts +40 -0
- package/dist/ptr/node/FileSystemUtils.d.ts.map +1 -0
- package/dist/ptr/node/FileSystemUtils.js +170 -0
- package/dist/ptr/node/FileSystemUtils.js.map +1 -0
- package/dist/ptr/node/NetworkConfig.d.ts +191 -0
- package/dist/ptr/node/NetworkConfig.d.ts.map +1 -0
- package/dist/ptr/node/NetworkConfig.js +8 -0
- package/dist/ptr/node/NetworkConfig.js.map +1 -0
- package/dist/ptr/node/NetworkRuntime.d.ts +38 -0
- package/dist/ptr/node/NetworkRuntime.d.ts.map +1 -0
- package/dist/ptr/node/NetworkRuntime.js +871 -0
- package/dist/ptr/node/NetworkRuntime.js.map +1 -0
- package/dist/ptr/node/P2PChatSession.d.ts +53 -0
- package/dist/ptr/node/P2PChatSession.d.ts.map +1 -0
- package/dist/ptr/node/P2PChatSession.js +154 -0
- package/dist/ptr/node/P2PChatSession.js.map +1 -0
- package/dist/ptr/node/RuntimeInterface.d.ts +4 -0
- package/dist/ptr/node/RuntimeInterface.d.ts.map +1 -0
- package/dist/ptr/node/RuntimeInterface.js +2 -0
- package/dist/ptr/node/RuntimeInterface.js.map +1 -0
- package/dist/ptr/node/Runtimes.d.ts +34 -0
- package/dist/ptr/node/Runtimes.d.ts.map +1 -0
- package/dist/ptr/node/Runtimes.js +38 -0
- package/dist/ptr/node/Runtimes.js.map +1 -0
- package/dist/ptr/node/SignalingServer.d.ts +37 -0
- package/dist/ptr/node/SignalingServer.d.ts.map +1 -0
- package/dist/ptr/node/SignalingServer.js +218 -0
- package/dist/ptr/node/SignalingServer.js.map +1 -0
- package/dist/ptr/node/cli.d.ts +3 -0
- package/dist/ptr/node/cli.d.ts.map +1 -0
- package/dist/ptr/node/cli.js +266 -0
- package/dist/ptr/node/cli.js.map +1 -0
- package/dist/ptr/node/clm/builtins/handle.d.ts +14 -0
- package/dist/ptr/node/clm/builtins/handle.d.ts.map +1 -0
- package/dist/ptr/node/clm/builtins/handle.js +177 -0
- package/dist/ptr/node/clm/builtins/handle.js.map +1 -0
- package/dist/ptr/node/clm/builtins/index.d.ts +20 -0
- package/dist/ptr/node/clm/builtins/index.d.ts.map +1 -0
- package/dist/ptr/node/clm/builtins/index.js +60 -0
- package/dist/ptr/node/clm/builtins/index.js.map +1 -0
- package/dist/ptr/node/clm/index.d.ts +25 -0
- package/dist/ptr/node/clm/index.d.ts.map +1 -0
- package/dist/ptr/node/clm/index.js +28 -0
- package/dist/ptr/node/clm/index.js.map +1 -0
- package/dist/ptr/node/clm/loader.d.ts +25 -0
- package/dist/ptr/node/clm/loader.d.ts.map +1 -0
- package/dist/ptr/node/clm/loader.js +146 -0
- package/dist/ptr/node/clm/loader.js.map +1 -0
- package/dist/ptr/node/clm/multiruntime.d.ts +9 -0
- package/dist/ptr/node/clm/multiruntime.d.ts.map +1 -0
- package/dist/ptr/node/clm/multiruntime.js +121 -0
- package/dist/ptr/node/clm/multiruntime.js.map +1 -0
- package/dist/ptr/node/clm/runner.d.ts +70 -0
- package/dist/ptr/node/clm/runner.d.ts.map +1 -0
- package/dist/ptr/node/clm/runner.js +324 -0
- package/dist/ptr/node/clm/runner.js.map +1 -0
- package/dist/ptr/node/clm/types.d.ts +166 -0
- package/dist/ptr/node/clm/types.d.ts.map +1 -0
- package/dist/ptr/node/clm/types.js +5 -0
- package/dist/ptr/node/clm/types.js.map +1 -0
- package/dist/ptr/node/clm/utils.d.ts +29 -0
- package/dist/ptr/node/clm/utils.d.ts.map +1 -0
- package/dist/ptr/node/clm/utils.js +88 -0
- package/dist/ptr/node/clm/utils.js.map +1 -0
- package/dist/ptr/node/network/HttpClient.d.ts +14 -0
- package/dist/ptr/node/network/HttpClient.d.ts.map +1 -0
- package/dist/ptr/node/network/HttpClient.js +139 -0
- package/dist/ptr/node/network/HttpClient.js.map +1 -0
- package/dist/ptr/node/network/MCardSerialization.d.ts +19 -0
- package/dist/ptr/node/network/MCardSerialization.d.ts.map +1 -0
- package/dist/ptr/node/network/MCardSerialization.js +41 -0
- package/dist/ptr/node/network/MCardSerialization.js.map +1 -0
- package/dist/ptr/node/network/NetworkInfrastructure.d.ts +37 -0
- package/dist/ptr/node/network/NetworkInfrastructure.d.ts.map +1 -0
- package/dist/ptr/node/network/NetworkInfrastructure.js +121 -0
- package/dist/ptr/node/network/NetworkInfrastructure.js.map +1 -0
- package/dist/ptr/node/network/NetworkSecurity.d.ts +24 -0
- package/dist/ptr/node/network/NetworkSecurity.d.ts.map +1 -0
- package/dist/ptr/node/network/NetworkSecurity.js +104 -0
- package/dist/ptr/node/network/NetworkSecurity.js.map +1 -0
- package/dist/ptr/node/runtimes/base.d.ts +31 -0
- package/dist/ptr/node/runtimes/base.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/base.js +33 -0
- package/dist/ptr/node/runtimes/base.js.map +1 -0
- package/dist/ptr/node/runtimes/binary.d.ts +10 -0
- package/dist/ptr/node/runtimes/binary.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/binary.js +16 -0
- package/dist/ptr/node/runtimes/binary.js.map +1 -0
- package/dist/ptr/node/runtimes/factory.d.ts +22 -0
- package/dist/ptr/node/runtimes/factory.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/factory.js +152 -0
- package/dist/ptr/node/runtimes/factory.js.map +1 -0
- package/dist/ptr/node/runtimes/index.d.ts +28 -0
- package/dist/ptr/node/runtimes/index.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/index.js +30 -0
- package/dist/ptr/node/runtimes/index.js.map +1 -0
- package/dist/ptr/node/runtimes/javascript.d.ts +22 -0
- package/dist/ptr/node/runtimes/javascript.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/javascript.js +125 -0
- package/dist/ptr/node/runtimes/javascript.js.map +1 -0
- package/dist/ptr/node/runtimes/lean.d.ts +10 -0
- package/dist/ptr/node/runtimes/lean.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/lean.js +60 -0
- package/dist/ptr/node/runtimes/lean.js.map +1 -0
- package/dist/ptr/node/runtimes/loader.d.ts +21 -0
- package/dist/ptr/node/runtimes/loader.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/loader.js +126 -0
- package/dist/ptr/node/runtimes/loader.js.map +1 -0
- package/dist/ptr/node/runtimes/python.d.ts +14 -0
- package/dist/ptr/node/runtimes/python.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/python.js +100 -0
- package/dist/ptr/node/runtimes/python.js.map +1 -0
- package/dist/ptr/node/runtimes/wasm.d.ts +10 -0
- package/dist/ptr/node/runtimes/wasm.d.ts.map +1 -0
- package/dist/ptr/node/runtimes/wasm.js +55 -0
- package/dist/ptr/node/runtimes/wasm.js.map +1 -0
- package/dist/rag/GraphRAGEngine.d.ts +26 -0
- package/dist/rag/GraphRAGEngine.d.ts.map +1 -0
- package/dist/rag/GraphRAGEngine.js +166 -0
- package/dist/rag/GraphRAGEngine.js.map +1 -0
- package/dist/rag/HandleVectorStore.d.ts +201 -0
- package/dist/rag/HandleVectorStore.d.ts.map +1 -0
- package/dist/rag/HandleVectorStore.js +527 -0
- package/dist/rag/HandleVectorStore.js.map +1 -0
- package/dist/rag/PersistentIndexer.d.ts +148 -0
- package/dist/rag/PersistentIndexer.d.ts.map +1 -0
- package/dist/rag/PersistentIndexer.js +302 -0
- package/dist/rag/PersistentIndexer.js.map +1 -0
- package/dist/rag/embeddings/VisionEmbeddingProvider.d.ts +87 -0
- package/dist/rag/embeddings/VisionEmbeddingProvider.d.ts.map +1 -0
- package/dist/rag/embeddings/VisionEmbeddingProvider.js +164 -0
- package/dist/rag/embeddings/VisionEmbeddingProvider.js.map +1 -0
- package/dist/rag/graph/community.d.ts +56 -0
- package/dist/rag/graph/community.d.ts.map +1 -0
- package/dist/rag/graph/community.js +247 -0
- package/dist/rag/graph/community.js.map +1 -0
- package/dist/rag/graph/extractor.d.ts +99 -0
- package/dist/rag/graph/extractor.d.ts.map +1 -0
- package/dist/rag/graph/extractor.js +210 -0
- package/dist/rag/graph/extractor.js.map +1 -0
- package/dist/rag/graph/store.d.ts +176 -0
- package/dist/rag/graph/store.d.ts.map +1 -0
- package/dist/rag/graph/store.js +504 -0
- package/dist/rag/graph/store.js.map +1 -0
- package/dist/rag/index.d.ts +20 -0
- package/dist/rag/index.d.ts.map +1 -0
- package/dist/rag/index.js +26 -0
- package/dist/rag/index.js.map +1 -0
- package/dist/rag/semanticVersioning.d.ts +187 -0
- package/dist/rag/semanticVersioning.d.ts.map +1 -0
- package/dist/rag/semanticVersioning.js +253 -0
- package/dist/rag/semanticVersioning.js.map +1 -0
- package/dist/storage/IndexedDBEngine.d.ts +33 -0
- package/dist/storage/IndexedDBEngine.d.ts.map +1 -0
- package/dist/storage/IndexedDBEngine.js +198 -0
- package/dist/storage/IndexedDBEngine.js.map +1 -0
- package/dist/storage/SqliteNodeEngine.d.ts +123 -0
- package/dist/storage/SqliteNodeEngine.d.ts.map +1 -0
- package/dist/storage/SqliteNodeEngine.js +385 -0
- package/dist/storage/SqliteNodeEngine.js.map +1 -0
- package/dist/storage/SqliteWasmEngine.d.ts +60 -0
- package/dist/storage/SqliteWasmEngine.d.ts.map +1 -0
- package/dist/storage/SqliteWasmEngine.js +193 -0
- package/dist/storage/SqliteWasmEngine.js.map +1 -0
- package/dist/storage/StorageAdapter.d.ts +42 -0
- package/dist/storage/StorageAdapter.d.ts.map +1 -0
- package/dist/storage/StorageAdapter.js +2 -0
- package/dist/storage/StorageAdapter.js.map +1 -0
- package/dist/storage/VectorStore.d.ts +202 -0
- package/dist/storage/VectorStore.d.ts.map +1 -0
- package/dist/storage/VectorStore.js +557 -0
- package/dist/storage/VectorStore.js.map +1 -0
- package/dist/storage/schema.d.ts +162 -0
- package/dist/storage/schema.d.ts.map +1 -0
- package/dist/storage/schema.js +373 -0
- package/dist/storage/schema.js.map +1 -0
- package/dist/util/FileIO.d.ts +44 -0
- package/dist/util/FileIO.d.ts.map +1 -0
- package/dist/util/FileIO.js +203 -0
- package/dist/util/FileIO.js.map +1 -0
- package/dist/util/Loader.d.ts +34 -0
- package/dist/util/Loader.d.ts.map +1 -0
- package/dist/util/Loader.js +168 -0
- package/dist/util/Loader.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alpha Conversion (α-conversion)
|
|
3
|
+
*
|
|
4
|
+
* Renames bound variables in Lambda terms while preserving meaning.
|
|
5
|
+
*
|
|
6
|
+
* Rule: λx.M ≡α λy.M[x:=y] (where y is fresh)
|
|
7
|
+
*
|
|
8
|
+
* Alpha conversion is the basis of variable renaming and is essential
|
|
9
|
+
* for avoiding variable capture during beta reduction.
|
|
10
|
+
*
|
|
11
|
+
* @module mcard-js/ptr/lambda/AlphaConversion
|
|
12
|
+
*/
|
|
13
|
+
import { loadTerm, storeTerm, mkVar, mkAbs, mkApp, isAbs } from './LambdaTerm';
|
|
14
|
+
import { freeVariables } from './FreeVariables';
|
|
15
|
+
import { IO } from '../../monads/IO';
|
|
16
|
+
import { Either } from '../../monads/Either';
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
// Alpha Conversion
|
|
19
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
/**
|
|
21
|
+
* Alpha-rename: Rename the bound variable of an abstraction
|
|
22
|
+
*
|
|
23
|
+
* λx.M → λy.M[x:=y]
|
|
24
|
+
*
|
|
25
|
+
* @param collection - Card collection for term storage
|
|
26
|
+
* @param absHash - Hash of the abstraction term
|
|
27
|
+
* @param newParam - New name for the bound variable
|
|
28
|
+
* @returns IO<Either<error, newHash>>
|
|
29
|
+
*/
|
|
30
|
+
export function alphaRename(collection, absHash, newParam) {
|
|
31
|
+
return IO.of(async () => {
|
|
32
|
+
const term = await loadTerm(collection, absHash);
|
|
33
|
+
if (!term) {
|
|
34
|
+
return Either.left(`Term not found: ${absHash}`);
|
|
35
|
+
}
|
|
36
|
+
if (!isAbs(term)) {
|
|
37
|
+
return Either.left(`Alpha conversion only applies to abstractions, got ${term.tag}`);
|
|
38
|
+
}
|
|
39
|
+
// If same name, no change needed
|
|
40
|
+
if (term.param === newParam) {
|
|
41
|
+
return Either.right(absHash);
|
|
42
|
+
}
|
|
43
|
+
// Check that new name doesn't capture free variables in body
|
|
44
|
+
const bodyFV = await freeVariables(collection, term.body).run();
|
|
45
|
+
if (bodyFV.isJust && bodyFV.value.has(newParam)) {
|
|
46
|
+
return Either.left(`Cannot α-rename to '${newParam}': would capture free variable in body`);
|
|
47
|
+
}
|
|
48
|
+
// Substitute old param with new param in body
|
|
49
|
+
const newBodyHash = await substituteVar(collection, term.body, term.param, newParam);
|
|
50
|
+
// Create new abstraction
|
|
51
|
+
const newAbs = mkAbs(newParam, newBodyHash);
|
|
52
|
+
const resultHash = await storeTerm(collection, newAbs);
|
|
53
|
+
return Either.right(resultHash);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Substitute a variable with another variable name throughout a term
|
|
58
|
+
*
|
|
59
|
+
* M[x:=y] - replaces all free occurrences of x with y
|
|
60
|
+
*/
|
|
61
|
+
async function substituteVar(collection, termHash, oldVar, newVar) {
|
|
62
|
+
const term = await loadTerm(collection, termHash);
|
|
63
|
+
if (!term) {
|
|
64
|
+
throw new Error(`Term not found: ${termHash}`);
|
|
65
|
+
}
|
|
66
|
+
switch (term.tag) {
|
|
67
|
+
case 'Var':
|
|
68
|
+
if (term.name === oldVar) {
|
|
69
|
+
// Replace with new variable
|
|
70
|
+
const newTerm = mkVar(newVar);
|
|
71
|
+
return storeTerm(collection, newTerm);
|
|
72
|
+
}
|
|
73
|
+
// Different variable, unchanged
|
|
74
|
+
return termHash;
|
|
75
|
+
case 'Abs':
|
|
76
|
+
if (term.param === oldVar) {
|
|
77
|
+
// Bound variable shadows, stop substitution
|
|
78
|
+
return termHash;
|
|
79
|
+
}
|
|
80
|
+
// Recurse into body
|
|
81
|
+
const newBody = await substituteVar(collection, term.body, oldVar, newVar);
|
|
82
|
+
if (newBody === term.body) {
|
|
83
|
+
// No change
|
|
84
|
+
return termHash;
|
|
85
|
+
}
|
|
86
|
+
const newAbs = mkAbs(term.param, newBody);
|
|
87
|
+
return storeTerm(collection, newAbs);
|
|
88
|
+
case 'App':
|
|
89
|
+
const newFunc = await substituteVar(collection, term.func, oldVar, newVar);
|
|
90
|
+
const newArg = await substituteVar(collection, term.arg, oldVar, newVar);
|
|
91
|
+
if (newFunc === term.func && newArg === term.arg) {
|
|
92
|
+
// No change
|
|
93
|
+
return termHash;
|
|
94
|
+
}
|
|
95
|
+
const newApp = mkApp(newFunc, newArg);
|
|
96
|
+
return storeTerm(collection, newApp);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
100
|
+
// Alpha Equivalence
|
|
101
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Check if two terms are alpha-equivalent
|
|
104
|
+
*
|
|
105
|
+
* Two terms are α-equivalent if they differ only in the names of bound variables.
|
|
106
|
+
*
|
|
107
|
+
* Note: If hashes are equal, terms are definitionally identical (stronger than α-equiv).
|
|
108
|
+
*/
|
|
109
|
+
export function alphaEquivalent(collection, hash1, hash2) {
|
|
110
|
+
return IO.of(async () => {
|
|
111
|
+
// Same hash = identical terms
|
|
112
|
+
if (hash1 === hash2) {
|
|
113
|
+
return Either.right(true);
|
|
114
|
+
}
|
|
115
|
+
const term1 = await loadTerm(collection, hash1);
|
|
116
|
+
const term2 = await loadTerm(collection, hash2);
|
|
117
|
+
if (!term1)
|
|
118
|
+
return Either.left(`Term not found: ${hash1}`);
|
|
119
|
+
if (!term2)
|
|
120
|
+
return Either.left(`Term not found: ${hash2}`);
|
|
121
|
+
const equiv = await checkAlphaEquiv(collection, term1, term2, new Map(), new Map());
|
|
122
|
+
return Either.right(equiv);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Internal alpha-equivalence check with variable renaming maps
|
|
127
|
+
*/
|
|
128
|
+
async function checkAlphaEquiv(collection, term1, term2, rename1, // Maps var name in term1 to de Bruijn index
|
|
129
|
+
rename2 // Maps var name in term2 to de Bruijn index
|
|
130
|
+
) {
|
|
131
|
+
if (term1.tag !== term2.tag) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
switch (term1.tag) {
|
|
135
|
+
case 'Var': {
|
|
136
|
+
const t2 = term2;
|
|
137
|
+
const idx1 = rename1.get(term1.name);
|
|
138
|
+
const idx2 = rename2.get(t2.name);
|
|
139
|
+
if (idx1 !== undefined && idx2 !== undefined) {
|
|
140
|
+
// Both are bound variables - compare by binding depth
|
|
141
|
+
return idx1 === idx2;
|
|
142
|
+
}
|
|
143
|
+
if (idx1 === undefined && idx2 === undefined) {
|
|
144
|
+
// Both are free variables - compare by name
|
|
145
|
+
return term1.name === t2.name;
|
|
146
|
+
}
|
|
147
|
+
// One bound, one free - not equivalent
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
case 'Abs': {
|
|
151
|
+
const t2 = term2;
|
|
152
|
+
// Extend renaming maps with new binding
|
|
153
|
+
const depth = rename1.size;
|
|
154
|
+
const newRename1 = new Map(rename1);
|
|
155
|
+
const newRename2 = new Map(rename2);
|
|
156
|
+
newRename1.set(term1.param, depth);
|
|
157
|
+
newRename2.set(t2.param, depth);
|
|
158
|
+
// Load and compare bodies
|
|
159
|
+
const body1 = await loadTerm(collection, term1.body);
|
|
160
|
+
const body2 = await loadTerm(collection, t2.body);
|
|
161
|
+
if (!body1 || !body2)
|
|
162
|
+
return false;
|
|
163
|
+
return checkAlphaEquiv(collection, body1, body2, newRename1, newRename2);
|
|
164
|
+
}
|
|
165
|
+
case 'App': {
|
|
166
|
+
const t2 = term2;
|
|
167
|
+
const func1 = await loadTerm(collection, term1.func);
|
|
168
|
+
const func2 = await loadTerm(collection, t2.func);
|
|
169
|
+
const arg1 = await loadTerm(collection, term1.arg);
|
|
170
|
+
const arg2 = await loadTerm(collection, t2.arg);
|
|
171
|
+
if (!func1 || !func2 || !arg1 || !arg2)
|
|
172
|
+
return false;
|
|
173
|
+
const funcEquiv = await checkAlphaEquiv(collection, func1, func2, rename1, rename2);
|
|
174
|
+
if (!funcEquiv)
|
|
175
|
+
return false;
|
|
176
|
+
return checkAlphaEquiv(collection, arg1, arg2, rename1, rename2);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
181
|
+
// Alpha Normalization (De Bruijn-like canonical form)
|
|
182
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
183
|
+
/**
|
|
184
|
+
* Alpha-normalize a term using canonical variable names
|
|
185
|
+
*
|
|
186
|
+
* All bound variables are renamed to a₀, a₁, a₂... based on binding depth.
|
|
187
|
+
* This produces a canonical representative of the α-equivalence class.
|
|
188
|
+
*/
|
|
189
|
+
export function alphaNormalize(collection, termHash) {
|
|
190
|
+
return IO.of(async () => {
|
|
191
|
+
const result = await normalizeWithDepth(collection, termHash, new Map(), 0);
|
|
192
|
+
if (result === null) {
|
|
193
|
+
return Either.left(`Term not found: ${termHash}`);
|
|
194
|
+
}
|
|
195
|
+
return Either.right(result);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Internal normalization with depth tracking
|
|
200
|
+
*/
|
|
201
|
+
async function normalizeWithDepth(collection, termHash, bindings, // original name -> canonical name
|
|
202
|
+
depth) {
|
|
203
|
+
const term = await loadTerm(collection, termHash);
|
|
204
|
+
if (!term)
|
|
205
|
+
return null;
|
|
206
|
+
switch (term.tag) {
|
|
207
|
+
case 'Var': {
|
|
208
|
+
const canonicalName = bindings.get(term.name);
|
|
209
|
+
if (canonicalName) {
|
|
210
|
+
// Bound variable - use canonical name
|
|
211
|
+
const newVar = mkVar(canonicalName);
|
|
212
|
+
return storeTerm(collection, newVar);
|
|
213
|
+
}
|
|
214
|
+
// Free variable - keep original name
|
|
215
|
+
return termHash;
|
|
216
|
+
}
|
|
217
|
+
case 'Abs': {
|
|
218
|
+
// Generate canonical name for this binding depth
|
|
219
|
+
const canonicalName = `a${depth}`;
|
|
220
|
+
// Extend bindings
|
|
221
|
+
const newBindings = new Map(bindings);
|
|
222
|
+
newBindings.set(term.param, canonicalName);
|
|
223
|
+
// Normalize body
|
|
224
|
+
const newBody = await normalizeWithDepth(collection, term.body, newBindings, depth + 1);
|
|
225
|
+
if (newBody === null)
|
|
226
|
+
return null;
|
|
227
|
+
const newAbs = mkAbs(canonicalName, newBody);
|
|
228
|
+
return storeTerm(collection, newAbs);
|
|
229
|
+
}
|
|
230
|
+
case 'App': {
|
|
231
|
+
const newFunc = await normalizeWithDepth(collection, term.func, bindings, depth);
|
|
232
|
+
const newArg = await normalizeWithDepth(collection, term.arg, bindings, depth);
|
|
233
|
+
if (newFunc === null || newArg === null)
|
|
234
|
+
return null;
|
|
235
|
+
// If unchanged, return original
|
|
236
|
+
if (newFunc === term.func && newArg === term.arg) {
|
|
237
|
+
return termHash;
|
|
238
|
+
}
|
|
239
|
+
const newApp = mkApp(newFunc, newArg);
|
|
240
|
+
return storeTerm(collection, newApp);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=AlphaConversion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlphaConversion.js","sourceRoot":"","sources":["../../../src/ptr/lambda/AlphaConversion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beta Reduction (β-reduction)
|
|
3
|
+
*
|
|
4
|
+
* The computational heart of Lambda Calculus - function application.
|
|
5
|
+
*
|
|
6
|
+
* Rule: (λx.M) N →β M[x:=N]
|
|
7
|
+
*
|
|
8
|
+
* A term of the form (λx.M) N is called a "beta-redex" (reducible expression).
|
|
9
|
+
* Beta reduction substitutes the argument N for all free occurrences of x in M.
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT: Must handle capture avoidance - if N contains free variables
|
|
12
|
+
* that would become bound in M, we must α-rename first.
|
|
13
|
+
*
|
|
14
|
+
* @module mcard-js/ptr/lambda/BetaReduction
|
|
15
|
+
*/
|
|
16
|
+
import { CardCollection } from '../../model/CardCollection';
|
|
17
|
+
import { IO } from '../../monads/IO';
|
|
18
|
+
import { Either } from '../../monads/Either';
|
|
19
|
+
import { Maybe } from '../../monads/Maybe';
|
|
20
|
+
/**
|
|
21
|
+
* Check if a term is a beta-redex: (λx.M) N
|
|
22
|
+
*/
|
|
23
|
+
export declare function isRedex(collection: CardCollection, termHash: string): IO<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* Find the leftmost-outermost redex (normal order reduction)
|
|
26
|
+
* Returns Maybe<hash of redex>
|
|
27
|
+
*/
|
|
28
|
+
export declare function findLeftmostRedex(collection: CardCollection, termHash: string): IO<Maybe<string>>;
|
|
29
|
+
/**
|
|
30
|
+
* Find the leftmost-innermost redex (applicative order reduction)
|
|
31
|
+
*/
|
|
32
|
+
export declare function findInnermostRedex(collection: CardCollection, termHash: string): IO<Maybe<string>>;
|
|
33
|
+
/**
|
|
34
|
+
* Perform a single beta reduction step on a redex
|
|
35
|
+
*
|
|
36
|
+
* (λx.M) N →β M[x:=N]
|
|
37
|
+
*
|
|
38
|
+
* @param collection - Card collection
|
|
39
|
+
* @param redexHash - Hash of the application term (λx.M) N
|
|
40
|
+
* @returns Either<error, resultHash>
|
|
41
|
+
*/
|
|
42
|
+
export declare function betaReduce(collection: CardCollection, redexHash: string): IO<Either<string, string>>;
|
|
43
|
+
export type ReductionStrategy = 'normal' | 'applicative' | 'lazy';
|
|
44
|
+
/**
|
|
45
|
+
* Perform one reduction step using the specified strategy
|
|
46
|
+
*/
|
|
47
|
+
export declare function reduceStep(collection: CardCollection, termHash: string, strategy?: ReductionStrategy): IO<Maybe<string>>;
|
|
48
|
+
export interface NormalizationResult {
|
|
49
|
+
normalForm: string;
|
|
50
|
+
steps: number;
|
|
51
|
+
reductionPath: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Normalize a term to its normal form (no more redexes)
|
|
55
|
+
*
|
|
56
|
+
* @param collection - Card collection
|
|
57
|
+
* @param termHash - Starting term
|
|
58
|
+
* @param strategy - Reduction strategy
|
|
59
|
+
* @param maxSteps - Maximum reduction steps (prevent infinite loops)
|
|
60
|
+
* @returns Either<error, NormalizationResult>
|
|
61
|
+
*/
|
|
62
|
+
export declare function normalize(collection: CardCollection, termHash: string, strategy?: ReductionStrategy, maxSteps?: number): IO<Either<string, NormalizationResult>>;
|
|
63
|
+
/**
|
|
64
|
+
* Check if a term is in normal form (has no redexes)
|
|
65
|
+
*/
|
|
66
|
+
export declare function isNormalForm(collection: CardCollection, termHash: string): IO<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* Check if a term has a normal form (is normalizing)
|
|
69
|
+
*
|
|
70
|
+
* Note: This is undecidable in general, so we use a bounded check
|
|
71
|
+
*/
|
|
72
|
+
export declare function hasNormalForm(collection: CardCollection, termHash: string, maxSteps?: number): IO<boolean>;
|
|
73
|
+
//# sourceMappingURL=BetaReduction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BetaReduction.d.ts","sourceRoot":"","sources":["../../../src/ptr/lambda/BetaReduction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAgB5D,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAM3C;;GAEG;AACH,wBAAgB,OAAO,CACnB,UAAU,EAAE,cAAc,EAC1B,QAAQ,EAAE,MAAM,GACjB,EAAE,CAAC,OAAO,CAAC,CAQb;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC7B,UAAU,EAAE,cAAc,EAC1B,QAAQ,EAAE,MAAM,GACjB,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAInB;AAmCD;;GAEG;AACH,wBAAgB,kBAAkB,CAC9B,UAAU,EAAE,cAAc,EAC1B,QAAQ,EAAE,MAAM,GACjB,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAInB;AAuCD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACtB,UAAU,EAAE,cAAc,EAC1B,SAAS,EAAE,MAAM,GAClB,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAkC5B;AA+GD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAC;AAElE;;GAEG;AACH,wBAAgB,UAAU,CACtB,UAAU,EAAE,cAAc,EAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,iBAA4B,GACvC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CA8CnB;AA8DD,MAAM,WAAW,mBAAmB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACrB,UAAU,EAAE,cAAc,EAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,iBAA4B,EACtC,QAAQ,GAAE,MAAa,GACxB,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CA2BzC;AAED;;GAEG;AACH,wBAAgB,YAAY,CACxB,UAAU,EAAE,cAAc,EAC1B,QAAQ,EAAE,MAAM,GACjB,EAAE,CAAC,OAAO,CAAC,CAEb;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CACzB,UAAU,EAAE,cAAc,EAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAa,GACxB,EAAE,CAAC,OAAO,CAAC,CAGb"}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beta Reduction (β-reduction)
|
|
3
|
+
*
|
|
4
|
+
* The computational heart of Lambda Calculus - function application.
|
|
5
|
+
*
|
|
6
|
+
* Rule: (λx.M) N →β M[x:=N]
|
|
7
|
+
*
|
|
8
|
+
* A term of the form (λx.M) N is called a "beta-redex" (reducible expression).
|
|
9
|
+
* Beta reduction substitutes the argument N for all free occurrences of x in M.
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT: Must handle capture avoidance - if N contains free variables
|
|
12
|
+
* that would become bound in M, we must α-rename first.
|
|
13
|
+
*
|
|
14
|
+
* @module mcard-js/ptr/lambda/BetaReduction
|
|
15
|
+
*/
|
|
16
|
+
import { loadTerm, storeTerm, mkAbs, mkApp, isAbs, isApp } from './LambdaTerm';
|
|
17
|
+
import { freeVariables, generateFresh } from './FreeVariables';
|
|
18
|
+
import { alphaRename } from './AlphaConversion';
|
|
19
|
+
import { IO } from '../../monads/IO';
|
|
20
|
+
import { Either } from '../../monads/Either';
|
|
21
|
+
import { Maybe } from '../../monads/Maybe';
|
|
22
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
// Beta Redex Detection
|
|
24
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* Check if a term is a beta-redex: (λx.M) N
|
|
27
|
+
*/
|
|
28
|
+
export function isRedex(collection, termHash) {
|
|
29
|
+
return IO.of(async () => {
|
|
30
|
+
const term = await loadTerm(collection, termHash);
|
|
31
|
+
if (!term || !isApp(term))
|
|
32
|
+
return false;
|
|
33
|
+
const func = await loadTerm(collection, term.func);
|
|
34
|
+
return func !== null && isAbs(func);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Find the leftmost-outermost redex (normal order reduction)
|
|
39
|
+
* Returns Maybe<hash of redex>
|
|
40
|
+
*/
|
|
41
|
+
export function findLeftmostRedex(collection, termHash) {
|
|
42
|
+
return IO.of(async () => {
|
|
43
|
+
return findRedexNormalOrder(collection, termHash);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function findRedexNormalOrder(collection, termHash) {
|
|
47
|
+
const term = await loadTerm(collection, termHash);
|
|
48
|
+
if (!term)
|
|
49
|
+
return Maybe.nothing();
|
|
50
|
+
switch (term.tag) {
|
|
51
|
+
case 'Var':
|
|
52
|
+
// Variables are not redexes
|
|
53
|
+
return Maybe.nothing();
|
|
54
|
+
case 'Abs':
|
|
55
|
+
// Look inside the body
|
|
56
|
+
return findRedexNormalOrder(collection, term.body);
|
|
57
|
+
case 'App': {
|
|
58
|
+
// Check if this application is a redex
|
|
59
|
+
const func = await loadTerm(collection, term.func);
|
|
60
|
+
if (func && isAbs(func)) {
|
|
61
|
+
// This is a redex!
|
|
62
|
+
return Maybe.just(termHash);
|
|
63
|
+
}
|
|
64
|
+
// Not a redex - search in func first (leftmost), then arg
|
|
65
|
+
const funcRedex = await findRedexNormalOrder(collection, term.func);
|
|
66
|
+
if (funcRedex.isJust)
|
|
67
|
+
return funcRedex;
|
|
68
|
+
return findRedexNormalOrder(collection, term.arg);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Find the leftmost-innermost redex (applicative order reduction)
|
|
74
|
+
*/
|
|
75
|
+
export function findInnermostRedex(collection, termHash) {
|
|
76
|
+
return IO.of(async () => {
|
|
77
|
+
return findRedexApplicativeOrder(collection, termHash);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async function findRedexApplicativeOrder(collection, termHash) {
|
|
81
|
+
const term = await loadTerm(collection, termHash);
|
|
82
|
+
if (!term)
|
|
83
|
+
return Maybe.nothing();
|
|
84
|
+
switch (term.tag) {
|
|
85
|
+
case 'Var':
|
|
86
|
+
return Maybe.nothing();
|
|
87
|
+
case 'Abs':
|
|
88
|
+
return findRedexApplicativeOrder(collection, term.body);
|
|
89
|
+
case 'App': {
|
|
90
|
+
// Search in subterms first (innermost)
|
|
91
|
+
const funcRedex = await findRedexApplicativeOrder(collection, term.func);
|
|
92
|
+
if (funcRedex.isJust)
|
|
93
|
+
return funcRedex;
|
|
94
|
+
const argRedex = await findRedexApplicativeOrder(collection, term.arg);
|
|
95
|
+
if (argRedex.isJust)
|
|
96
|
+
return argRedex;
|
|
97
|
+
// Then check if this is a redex
|
|
98
|
+
const func = await loadTerm(collection, term.func);
|
|
99
|
+
if (func && isAbs(func)) {
|
|
100
|
+
return Maybe.just(termHash);
|
|
101
|
+
}
|
|
102
|
+
return Maybe.nothing();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
107
|
+
// Beta Reduction
|
|
108
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
109
|
+
/**
|
|
110
|
+
* Perform a single beta reduction step on a redex
|
|
111
|
+
*
|
|
112
|
+
* (λx.M) N →β M[x:=N]
|
|
113
|
+
*
|
|
114
|
+
* @param collection - Card collection
|
|
115
|
+
* @param redexHash - Hash of the application term (λx.M) N
|
|
116
|
+
* @returns Either<error, resultHash>
|
|
117
|
+
*/
|
|
118
|
+
export function betaReduce(collection, redexHash) {
|
|
119
|
+
return IO.of(async () => {
|
|
120
|
+
const app = await loadTerm(collection, redexHash);
|
|
121
|
+
if (!app) {
|
|
122
|
+
return Either.left(`Term not found: ${redexHash}`);
|
|
123
|
+
}
|
|
124
|
+
if (!isApp(app)) {
|
|
125
|
+
return Either.left(`Beta reduction requires application term, got ${app.tag}`);
|
|
126
|
+
}
|
|
127
|
+
const func = await loadTerm(collection, app.func);
|
|
128
|
+
if (!func) {
|
|
129
|
+
return Either.left(`Function not found: ${app.func}`);
|
|
130
|
+
}
|
|
131
|
+
if (!isAbs(func)) {
|
|
132
|
+
return Either.left(`Not a beta-redex: function is ${func.tag}, not abstraction`);
|
|
133
|
+
}
|
|
134
|
+
// Perform substitution: M[x:=N]
|
|
135
|
+
const resultHash = await substituteWithCapture(collection, func.body, // M
|
|
136
|
+
func.param, // x
|
|
137
|
+
app.arg // N (as hash)
|
|
138
|
+
);
|
|
139
|
+
return Either.right(resultHash);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Substitute a variable with a term (by hash), handling capture avoidance
|
|
144
|
+
*
|
|
145
|
+
* M[x:=N] - replaces all free occurrences of x in M with N
|
|
146
|
+
*/
|
|
147
|
+
async function substituteWithCapture(collection, termHash, variable, replacementHash) {
|
|
148
|
+
const term = await loadTerm(collection, termHash);
|
|
149
|
+
if (!term) {
|
|
150
|
+
throw new Error(`Term not found: ${termHash}`);
|
|
151
|
+
}
|
|
152
|
+
switch (term.tag) {
|
|
153
|
+
case 'Var':
|
|
154
|
+
// If this is the variable we're substituting, return the replacement
|
|
155
|
+
if (term.name === variable) {
|
|
156
|
+
return replacementHash;
|
|
157
|
+
}
|
|
158
|
+
// Otherwise unchanged
|
|
159
|
+
return termHash;
|
|
160
|
+
case 'Abs': {
|
|
161
|
+
// If bound variable shadows, stop substitution
|
|
162
|
+
if (term.param === variable) {
|
|
163
|
+
return termHash;
|
|
164
|
+
}
|
|
165
|
+
// Check for variable capture:
|
|
166
|
+
// If the bound variable (term.param) is free in the replacement,
|
|
167
|
+
// we must α-rename to avoid capture
|
|
168
|
+
const replacementFV = await freeVariables(collection, replacementHash).run();
|
|
169
|
+
if (replacementFV.isJust && replacementFV.value.has(term.param)) {
|
|
170
|
+
// Capture would occur! Need to α-rename first
|
|
171
|
+
const allVars = new Set(replacementFV.value);
|
|
172
|
+
// Also avoid variables in the body
|
|
173
|
+
const bodyFV = await freeVariables(collection, term.body).run();
|
|
174
|
+
if (bodyFV.isJust) {
|
|
175
|
+
for (const v of bodyFV.value)
|
|
176
|
+
allVars.add(v);
|
|
177
|
+
}
|
|
178
|
+
allVars.add(variable);
|
|
179
|
+
// Generate fresh name
|
|
180
|
+
const freshName = generateFresh(term.param, allVars);
|
|
181
|
+
// α-rename the abstraction
|
|
182
|
+
const renameResult = await alphaRename(collection, termHash, freshName).run();
|
|
183
|
+
if (renameResult.isLeft) {
|
|
184
|
+
throw new Error(`Alpha rename failed: ${renameResult.left}`);
|
|
185
|
+
}
|
|
186
|
+
// Now substitute in the renamed term
|
|
187
|
+
return substituteWithCapture(collection, renameResult.right, variable, replacementHash);
|
|
188
|
+
}
|
|
189
|
+
// No capture - recurse into body
|
|
190
|
+
const newBody = await substituteWithCapture(collection, term.body, variable, replacementHash);
|
|
191
|
+
if (newBody === term.body) {
|
|
192
|
+
return termHash;
|
|
193
|
+
}
|
|
194
|
+
const newAbs = mkAbs(term.param, newBody);
|
|
195
|
+
return storeTerm(collection, newAbs);
|
|
196
|
+
}
|
|
197
|
+
case 'App': {
|
|
198
|
+
const newFunc = await substituteWithCapture(collection, term.func, variable, replacementHash);
|
|
199
|
+
const newArg = await substituteWithCapture(collection, term.arg, variable, replacementHash);
|
|
200
|
+
if (newFunc === term.func && newArg === term.arg) {
|
|
201
|
+
return termHash;
|
|
202
|
+
}
|
|
203
|
+
const newApp = mkApp(newFunc, newArg);
|
|
204
|
+
return storeTerm(collection, newApp);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Perform one reduction step using the specified strategy
|
|
210
|
+
*/
|
|
211
|
+
export function reduceStep(collection, termHash, strategy = 'normal') {
|
|
212
|
+
return IO.of(async () => {
|
|
213
|
+
// Find redex using strategy
|
|
214
|
+
let redexMaybe;
|
|
215
|
+
switch (strategy) {
|
|
216
|
+
case 'normal':
|
|
217
|
+
case 'lazy':
|
|
218
|
+
redexMaybe = await findRedexNormalOrder(collection, termHash);
|
|
219
|
+
break;
|
|
220
|
+
case 'applicative':
|
|
221
|
+
redexMaybe = await findRedexApplicativeOrder(collection, termHash);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
if (redexMaybe.isNothing) {
|
|
225
|
+
// No redex found - already in normal form
|
|
226
|
+
return Maybe.nothing();
|
|
227
|
+
}
|
|
228
|
+
const redexHash = redexMaybe.value;
|
|
229
|
+
// If the redex is the whole term, just reduce it
|
|
230
|
+
if (redexHash === termHash) {
|
|
231
|
+
const result = await betaReduce(collection, redexHash).run();
|
|
232
|
+
if (result.isLeft) {
|
|
233
|
+
throw new Error(result.left);
|
|
234
|
+
}
|
|
235
|
+
return Maybe.just(result.right);
|
|
236
|
+
}
|
|
237
|
+
// Otherwise, need to reduce the subterm and reconstruct
|
|
238
|
+
const reduced = await betaReduce(collection, redexHash).run();
|
|
239
|
+
if (reduced.isLeft) {
|
|
240
|
+
throw new Error(reduced.left);
|
|
241
|
+
}
|
|
242
|
+
const rebuilt = await rebuildWithReduced(collection, termHash, redexHash, reduced.right);
|
|
243
|
+
return Maybe.just(rebuilt);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Rebuild a term after reducing a subterm
|
|
248
|
+
*/
|
|
249
|
+
async function rebuildWithReduced(collection, termHash, redexHash, reducedHash) {
|
|
250
|
+
if (termHash === redexHash) {
|
|
251
|
+
return reducedHash;
|
|
252
|
+
}
|
|
253
|
+
const term = await loadTerm(collection, termHash);
|
|
254
|
+
if (!term)
|
|
255
|
+
throw new Error(`Term not found: ${termHash}`);
|
|
256
|
+
switch (term.tag) {
|
|
257
|
+
case 'Var':
|
|
258
|
+
return termHash;
|
|
259
|
+
case 'Abs': {
|
|
260
|
+
const newBody = await rebuildWithReduced(collection, term.body, redexHash, reducedHash);
|
|
261
|
+
if (newBody === term.body)
|
|
262
|
+
return termHash;
|
|
263
|
+
const newAbs = mkAbs(term.param, newBody);
|
|
264
|
+
return storeTerm(collection, newAbs);
|
|
265
|
+
}
|
|
266
|
+
case 'App': {
|
|
267
|
+
const newFunc = await rebuildWithReduced(collection, term.func, redexHash, reducedHash);
|
|
268
|
+
const newArg = await rebuildWithReduced(collection, term.arg, redexHash, reducedHash);
|
|
269
|
+
if (newFunc === term.func && newArg === term.arg)
|
|
270
|
+
return termHash;
|
|
271
|
+
const newApp = mkApp(newFunc, newArg);
|
|
272
|
+
return storeTerm(collection, newApp);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Normalize a term to its normal form (no more redexes)
|
|
278
|
+
*
|
|
279
|
+
* @param collection - Card collection
|
|
280
|
+
* @param termHash - Starting term
|
|
281
|
+
* @param strategy - Reduction strategy
|
|
282
|
+
* @param maxSteps - Maximum reduction steps (prevent infinite loops)
|
|
283
|
+
* @returns Either<error, NormalizationResult>
|
|
284
|
+
*/
|
|
285
|
+
export function normalize(collection, termHash, strategy = 'normal', maxSteps = 1000) {
|
|
286
|
+
return IO.of(async () => {
|
|
287
|
+
let current = termHash;
|
|
288
|
+
let steps = 0;
|
|
289
|
+
const path = [termHash];
|
|
290
|
+
while (steps < maxSteps) {
|
|
291
|
+
const stepResult = await reduceStep(collection, current, strategy).run();
|
|
292
|
+
if (stepResult.isNothing) {
|
|
293
|
+
// No more reductions - reached normal form
|
|
294
|
+
return Either.right({
|
|
295
|
+
normalForm: current,
|
|
296
|
+
steps,
|
|
297
|
+
reductionPath: path
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
current = stepResult.value;
|
|
301
|
+
path.push(current);
|
|
302
|
+
steps++;
|
|
303
|
+
}
|
|
304
|
+
return Either.left(`Normalization did not terminate within ${maxSteps} steps (possible infinite loop)`);
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Check if a term is in normal form (has no redexes)
|
|
309
|
+
*/
|
|
310
|
+
export function isNormalForm(collection, termHash) {
|
|
311
|
+
return findLeftmostRedex(collection, termHash).map(m => m.isNothing);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Check if a term has a normal form (is normalizing)
|
|
315
|
+
*
|
|
316
|
+
* Note: This is undecidable in general, so we use a bounded check
|
|
317
|
+
*/
|
|
318
|
+
export function hasNormalForm(collection, termHash, maxSteps = 1000) {
|
|
319
|
+
return normalize(collection, termHash, 'normal', maxSteps)
|
|
320
|
+
.map(result => result.isRight);
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=BetaReduction.js.map
|