背景:我正在Haskell写一个玩具Lisp(Scheme)解释器。我希望能够使用LLVM编译代码。我花了几天时间想出各种方法将无类型的Lisp值提供给编译函数,这些函数希望知道它们的数据格式。在我看来,我不是第一个需要解决这个问题的人。
问题:将无类型数据映射为高效二进制格式的历史成功方法是什么。
附录:事实上,我确实知道数据中的十几种不同类型,我只是不知道在编译时可能会将哪一种发送到该函数。函数本身需要一种方法来确定它得到了什么。
答案 0 :(得分:3)
你的意思是,“我只是不知道哪些[类型]可能被发送到运行时的功能”?并不是数据没有打字;当然1
和'()
有不同的类型。相反,数据不是静态类型的,即,在编译时不知道给定变量的类型是什么。这称为dynamic typing。
你是对的,你不是第一个需要解决这个问题的人。规范解决方案是标记每个运行时值及其类型。例如,如果您有十几种类型,请将它们编号为:
cons
对完成此操作后,请为标记保留每个单词的前四位。然后,每次将两个对象传入+
时,首先执行一个简单的位掩码,以验证两个对象的前四位是0b0000,即它们都是整数。如果不是,则跳转到错误消息;否则,继续添加,并确保结果也相应标记。
这种技术本质上使得每个运行时值都是手动的 - tagged union,如果您使用过C,这对您来说应该很熟悉。事实上,它也像Haskell数据类型一样,除了在Haskell中标记性更加抽象。
如果您正在尝试编写Scheme编译器,我猜您熟悉指针。为避免限制可用内存空间,使用底部(最低有效)四位而不是顶部位可能更为敏感。更好的是,因为对齐的双字指针底部已经有三个无意义的位,所以只要取消引用实际地址而不是标记的地址,就可以简单地为这些位添加这些位。
这有帮助吗?
答案 1 :(得分:2)
您的默认解决方案应该是一个简单的标记联合。如果你想缩小你的打字范围到更具体的类型,你可以做到 - 但它不再是那个“玩具”了。需要注意的是abstract interpretation。