gpt4 book ai didi

haskell - 如何获得 IsString 实例中文字的编译时验证?

转载 作者:行者123 更新时间:2023-12-04 01:53:43 26 4
gpt4 key购买 nike

我希望能够制作 IsString使用 GHC OverloadedStrings 的实例扩展,以便我的实例拒绝一些无效的文字,并且这种拒绝发生在编译时,因此编程错误不会进入我提供给我的用户的代码。

我有几个用例,我有一个 Name只接受某些字符串的类型。例如

module Name (Name(getName), makeName) where

import Data.Text (Text)
import qualified Data.Text as Text

-- | A guaranteed non-empty name.
newtype Name = Name { getName :: Text } deriving (Eq, Show, Ord)

makeName :: Text -> Maybe Name
makeName name
| Text.null name = Nothing
| otherwise = Just name

在实际用例中,我会检查有效字符,而不是从数字开始,诸如此类。

我们的想法是我们不导出 Name构造函数,这意味着任何使用 Name 的人value 可以相信它具有某些属性(在这种情况下,非空)。

我的问题是我想在很多地方使用文字名称。例如
programName :: Name
programName = fromJust $ makeName "the-great-and-powerful-turtle"

因为我经常这样做,所以我定义了一个 unsafeMakeName做几乎相同的事情的助手:
unsafeMakeName :: Text -> Name
unsafeMakeName name = fromMaybe (error $ "Invalid name: " <> Text.unpack name) (makeName name)

这种方法的问题在于,即使错误的原因是编程错误,我直到运行时才发现它。

我想做的是写一个 IsString Name 的实例哪个进行验证,例如
instance IsString Name where
fromString = unsafeMakeName . Text.pack

...但是要在编译时获取有关文字中无效名称的错误。

当我尝试这个时,我似乎只在运行时得到错误,当使用文字值时。这不太理想,因为它在我的实际代码中是一个错误。

有什么办法可以做到这一点吗?这是可以在 GHC 中解决的问题吗?请注意,我已经 filed a bug那里。

最佳答案

听起来你真正想要的是 quasiquoter而不是 OverloadedStrings .然后验证逻辑进入 Q monad,在编译时运行。对于上面的简单示例:

{-# LANGUAGE QuasiQuotes, TemplateHaskell #-}

module Name (Name(getName), name) where

import Data.Text (Text)
import qualified Data.Text as Text

import Language.Haskell.TH.Quote hiding (Name)
import Language.Haskell.TH hiding (Name)

-- | A guaranteed non-empty name.
newtype Name = Name { getName :: Text } deriving (Eq, Show, Ord)

makeName :: String -> Q Exp
makeName name
| null name = fail "Invalid name"
| otherwise = [| Name (Text.pack name) |]

name :: QuasiQuoter
name = QuasiQuoter { quoteExp = makeName }

然后,在另一个模块中,以下编译:
{-# LANGUAGE QuasiQuotes #-}
import Name

main = print [name|valid-name|]

但以下没有,并吐出 Invalid name错误信息。
{-# LANGUAGE QuasiQuotes #-}
import Name

main = print [name||]

请注意,您也可以获得适用于模式的准引用器(因此 myFunc [name|valid-name|] = True 之类的可能是有效的函数定义)!

关于haskell - 如何获得 IsString 实例中文字的编译时验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41433445/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com