首页 文章

声明性编程中的实习字符串

提问于
浏览
2

以下场景显示了一个抽象,在我看来,无法以声明方式实现 .

假设我想创建一个Symbol对象,它允许您创建具有可比较字符串的对象,如Symbol.for() in JavaScript . JS中的简单实现可能如下所示:

function MySymbol(text){//Comparable symbol object class
  this.text = text;
  this.equals = function(other){//Method to compare to other MySymbol
    return this.text == other.text;
  }
}

我可以用像Haskell这样的声明性语言轻松编写它:

data MySymbol = MySymbol String

makeSymbol :: String -> MySymbol
makeSymbol s = MySymbol s

compareSymbol :: MySymbol -> MySymbol -> Bool
compareSymbol (MySymbol s1) (MySymbol s2) = s1 == s2

但是,也许将来我想通过使用MySymbol对象的全局注册表来提高效率 . (我 class 的用户没有改变它以使用注册表)

例如,这很容易在Javascript中完成:

function MySymbol(text){
  if (MySymbol.registry.has(text)){//check if symbol already in registry
    this.id = MySymbol.registry.get(text);//get id
  } else {
    this.id = MySymbol.nextId++;
    MySymbol.registry.set(text, this.id);//Add new symbol with nextId
  }
  this.equals = function(other){//To compare, simply compare ids
    return this.id == other.id;
  }
}
//Setup initial empty registry
MySymbol.registry = new Map();//A map from strings to numbers
MySymbol.nextId = 0;

但是,在Haskell中创建可变的全局注册表是不可能的 . (我可以创建一个注册表,但不能不改变我的函数的接口 . )


具体来说,这三种可能的Haskell解决方案都存在问题:

  • 强制用户传递注册表参数或等效项,使接口实现依赖

  • 使用一些像Haskell的Control.Monad.Random这样花哨的Monad东西,这需要从一开始就预见到优化或改变界面(基本上只是将状态的概念添加到你的程序中,因此打破了引用透明度等)

  • 执行缓慢,在给定的应用程序中可能不实用

这些解决方案都不允许我从Haskell接口中充分抽象出实现 .

So, my question is: 有没有办法在Haskell(或任何声明性语言)中对Symbol对象实现此优化,而不会导致上面列出的三个问题之一,并且是否存在命令式语言可以表达抽象的任何其他情况(例如优化)如上所述)声明性语言不能?

1 回答

  • 4

    intern package显示了如何 . 正如@luqui所讨论的那样,它在几个关键时刻使用 unsafePerformIO ,并且小心隐藏在实习期间产生的标识符 .

相关问题