嗨所以我得到了一个函数,它接受一个字符串并计算值,无论是int还是bool。该字符串可以是:“* let X = 3 in + X 1 2
”,表示“(let X = 3 in (X + 1)) * 2
”。如果我要求布尔,这将给我8或假。很简单。但我还想检查解析器中绑定变量的状态。即如果我使用像这个“* let X = 3 in + X 1 X
”这样的字符串作为输入,它将代表“(let X = 3 in (X + 1)) * X
”,这使得最后一个X不受约束。这将给我一个错误,说变量A是未绑定的或其他东西。
如果有人能给我任何关于如何做到这一点的想法,我将非常感激!
已解析字符串的示例:
((let X = 3 in (X + 1)) * 2)
会给我:
(Mul (Let (Vari X) (Lit (Single 3)) (Sum (Vari X) (Lit (Single 1)))) (Vari X))
所以我的问题基本上是如何检查解析后的字符串是否有任何未绑定的变量。
data Number = Single Int | Many Int Number deriving (Eq, Show)
data Expr = Vari Chara | Lit Number | Sub Expr | Sum Expr Expr | Mul Expr Expr | Let Expr Expr Expr | If Expr Expr Expr deriving (Eq, Show)
答案 0 :(得分:0)
重新解析解析后的表达式,并保存一组绑定变量。每当您遇到Let
时,请记录下来,每次遇到Var
时,请检查它是否在您的集合中,每次遇到其他内容时,请检查其子表达式。
checkVars' :: Set String -> Expr -> Bool
checkVars' bound (Var v) = S.member v set
checkVars' bound (Let var val expr) = checkVars' bound val && checkVars' (insert var bound) expr
checkVars' bound (Mul expr1 expr2) = checkVars' bound expr1 && checkVars' bound expr2
-- Similar for other ctors...
checkVars :: Expr -> Bool
checkVars = checkVars' S.empty
您也可以向相反的方向工作,从下到上构建一组自由变量,并在看到Let
约束时删除变量。 (这感觉更自然。)
freeVars :: Expr -> Set String
freeVars (Var v) = S.singleton v
freeVars (Let var val expr) = S.union (freeVars val) $ S.delete var $ freeVars expr
freeVars (Add expr1 expr2) = S.union expr1 expr2
-- etc.
checkVars :: Expr -> Bool
checkVars = S.null . freeVars
-- With recursion-schemes
data ExprF a = Add a a
| Mul a a
| Let String a a
| Var String
| Lit Int
deriving (Eq, Show, Read, Functor, Foldable, Traversable)
type Expr = Fix ExprF
freeVars :: Expr -> Set String
freeVars = cata go -- -XLambdaCase, anyone?
where go :: ExprF (Set String) -> Set String
go (Var var) = S.singleton var
go (Let var val expr) = S.union val $ S.delete var expr
go e = foldl S.union S.empty e -- Handle everything else
答案 1 :(得分:0)
我建议在带有绑定的语法中为变量(例如the extraordinarily useful bound
library提供的变量)使用本地无名表示。在本地无名表示中,使用de Bruijn索引表示绑定变量,使用名称表示未绑定变量。当涉及到α等价和捕获 - 避免替换等问题时,这可以为您节省大量的工作,并且回答问题"这个变量是否受约束?"变得非常直截了当。
通常,本地无名表示是表面语法树上作用域检查操作的输出。我们可以调整@HNTW's answer中的代码来生成已检查的术语,而不是Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy1.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:108)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 0
at org.springframework.core.MethodParameter.getGenericParameterType(MethodParameter.java:387)
at org.springframework.core.SerializableTypeWrapper$MethodParameterTypeProvider.getType(SerializableTypeWrapper.java:337)
at org.springframework.core.SerializableTypeWrapper.forTypeProvider(SerializableTypeWrapper.java:149)
at org.springframework.core.ResolvableType.forType(ResolvableType.java:1333)
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1249)
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1217)
at org.springframework.beans.factory.config.DependencyDescriptor.getResolvableType(DependencyDescriptor.java:246)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1193)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 49 more
:
Bool
data Scoped a = SVar a
| SLet (Scoped a) (Scope () Scoped a) -- The expression being let-bound, and the subexpression with the new variable in scope
| SLit Number
| SSub (Scoped a)
| SSum (Scoped a) (Scoped a)
| SMul (Scoped a) (Scoped a)
| SIf (Scoped a) (Scoped a) (Scoped a)
deriving (Functor, Foldable, Traversable)
instance Applicative Scoped where
pure = SVar
(<*>) = ap
instance Monad Scoped where
return = SVar
SVar a >>= g = g a
SLet expr scope >>= g = SLet (expr >>= g) (scope >>>= g)
SLit x >>= g = SLit x
SSub x >>= g = SSub (x >>= g)
SSum x y >>= g = SSum (x >>= g) (y >>= g)
SMul x y >>= g = SMul (x >>= g) (y >>= g)
SIf cond t f >>= g = SIf (cond >>= g) (t >>= g) (f >>= g)
scoped :: Expr -> Scoped Char
scoped (Var x) = SVar x
scoped (Let name expr sub) = SLet (scope expr) (abstract1 name $ scoped sub)
scoped (Lit x) = SLit x
scoped (Sub s) = SSub (scoped s)
scoped (Sum x y) = SSum (scoped x) (scoped y)
scoped (Mul x y) = SMul (scoped x) (scoped y)
scoped (If cond t f) = SIf (scoped cond) (scoped t) (scoped f)
将表达式视为&#34;容器&#34;名字bound
。 a
实例执行替换(Monad
接受函数映射名称(>>=) :: Scoped a -> (a -> Scoped b) -> Scoped b
到术语a
并将它们一起移植),Scoped b
库使用此替换操作来实现像abstract1
这样的工具,它绑定子表达式中的变量,以本地无名形式生成一个新的子表达式。
(取消单独的bound
类型并不是不合理的,只是直接生成Expr
作为解析器的输出。)
Scoped Char
&#39; Scoped
和Foldable
个实例可让您找到表达式中的所有未绑定变量。
Traversable
unboundVariables :: Scoped a -> [a]
unboundVariables = toList
&#39; isClosed
组合符可以满足您的需求:如果表达式有任何自由变量,它会返回bound
。
如果你在一个范围内走动,你需要知道一个特定的变量是绑定的还是免费的,你可以在Var
&#39; s False
和{{}上进行模式匹配。 1}}构造函数,或使用the supplied Prism
s:
B
有关F
工作原理的详情,请参阅this blog post或these slides。