问题描述
我正在尝试创建以下数据类型:
const IndexPage = () => {
const { keycloak } = useKeycloak<KeycloakInstance>()
const loggedinState = keycloak?.authenticated ? (
<span className="text-success">logged in</span>
) : (
<span className="text-danger">NOT logged in</span>
)
const welcomeMessage =
keycloak?.authenticated
? `Welcome back!`
: 'Welcome visitor. Please login to continue.'
return (
<Layout title="Home | Next.js + TypeScript Example">
<h1 className="mt-5">Hello Next.js + Keycloak ?</h1>
<div className="mb-5 lead text-muted">
This is an example of a Next.js site using Keycloak.
</div>
<p>You are: {loggedinState}</p>
<p>{welcomeMessage}</p>
</Layout>
)
}
export default IndexPage
但是,正如评论中所指出的,我希望 ExprFuncall 旁边的 Exprvalues 只接受 ExprIdent String,而不是其他 Exprvalues。我该怎么做?
解决方法
首先,如果你只想允许构造函数,为什么不直接“内联”它——在 String
中存储一个 ExprOverall
并完成?
但更普遍的是,这种限制可以通过 GADT 实现。通常,尤其是对于此类类似 AST 的类型,您希望表达表达式所代表的整体类型。在那里,ExprIdent
可能是多态的,而其他的则是具体的:
{-# LANGUAGE GADTs #-}
data ExprValues a where
ExprNum :: Int -> ExprValues Int
ExprIdent :: String -> ExprValues a
ExprChar :: Char -> ExprValues Char
ExprString :: String -> ExprValues String
然后,为了在 ExprOverall
中使用,您选择一个仅适用于 ExprIdent
构造函数的唯一标记类型(因为它允许任何类型变量 a
,而其他则是特定的到具体类型)。
data FreeIdentifier
data ExprOverall = ExprFunCall (ExprValues FreeIdentifier)