1

我想在编译时创建一个映射,将编译时键映射到运行时值。如果并非所有必需的键都存在,函数应该能够检查这些键并引发编译器错误。

这大致是我想要实现的目标:

class HasFirst a
  first :: String

class HasMiddle a
  middle :: String

class HasLast a
  last :: String

print_full_name :: (HasFirst a, HasLast a) => a -> String

addFirst :: String -> a -> b
addFirst s x = -- ( Add a first name to x )

emptyName :: -- some empty name

x1 = addFirst "John" $ addLast "Smith" $ emptyName
x2 = addMiddle "Bob" $ addLast "Smith" $ emptyName

main = putStr $ print_full_name x1 -- Compiles
main = putStr $ print_full_name x2 -- No first name so compile error

对于那些有 C++ 知识的人,我想大致了解boost::fusion::map的作用。

我不需要上面的代码,重要的是我可以在编译时检查参数。无论机制是类还是其他我不介意的东西。

是否有一个包可以做到这一点,或者开发它是否容易?

4

1 回答 1

7

让我告诉您如何使用称为幻像类型的功能设计技术使您的示例工作:

{-# LANGUAGE EmptyDataDecls #-}

data YES
data NO

data Name first middle last = Name String String String

emptyName :: Name NO NO NO
emptyName = Name "" "" ""

addFirst :: String -> Name first middle last -> Name YES middle last
addFirst s (Name a b c) = Name s b c

addMiddle :: String -> Name first middle last -> Name first YES last
addMiddle s (Name a b c) = Name a s c

addLast :: String -> Name first middle last -> Name first middle YES
addLast s (Name a b c) = Name a b s

printFullName :: Name YES middle YES -> String
printFullName (Name a b c) = a++b++c

我们使用 的三个类型参数Name来跟踪已设置的名称。printFullName只接受有名字和姓氏的名字。尝试打印未定义名称时出现类型错误:

*Main> printFullName $ addFirst "John" $ addLast "Smith" $ emptyName
"JohnSmith"
*Main> printFullName $ addFirst "John" $ addMiddle "Edward" $ emptyName

<interactive>:1:16:
    Couldn't match expected type `YES' against inferred type `NO'
      Expected type: Name YES YES YES
      Inferred type: Name YES YES NO
    In the second argument of `($)', namely
        `addFirst "John" $ addMiddle "Edward" $ emptyName'
    In the expression:
          printFullName $ addFirst "John" $ addMiddle "Edward" $ emptyName

请注意,这是一个非常粗略的编码,但希望它展示了幻像类型的力量。

于 2012-08-01T08:16:57.430 回答