Haskell - 限制数据参数

问题描述

我正在尝试创建以下数据类型:

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)