【问题标题】:On Church numeral program under Frege弗雷格下的教会数字程序
【发布时间】:2016-03-08 03:42:55
【问题描述】:

本程序在GHC下编译运行正常:

type Church a = (a -> a) -> a -> a

ch :: Int -> Church a
ch 0 _ = id
ch n f = f . ch (n-1) f

unch :: Church Int -> Int
unch n = n (+1) 0

suc :: Church a -> Church a
suc n f = f . n f

pre :: Church ((a -> a) -> a) -> Church a
pre n f a = n s z id
    where s g h = h (g f)
          z     = const a

main :: IO ()
main = do let seven = ch 7
              eight = suc seven
              six   = pre seven
          print (unch eight)
          print (unch six)

但是使用 Frege 编译时出现以下错误:

E /home/xgp/work/flab/src/main/frege/flab/fold.fr:23: type error in expression seven
    type is : Int
    expected: (t1→t1)→t1
E /home/xgp/work/flab/src/main/frege/flab/fold.fr:23: type error in expression seven
    type is : (t1→t1)→t1
    expected: Int
E /home/xgp/work/flab/src/main/frege/flab/fold.fr:23: type error in expression seven
    type is : (t1→t1)→t1
    expected: Int
E /home/xgp/work/flab/src/main/frege/flab/fold.fr:23: type error in
    expression seven
    type is apparently Int
    used as function

为什么?是否可以修改程序以通过Frege下的编译?

【问题讨论】:

  • 奇怪。但是将sixseveneight 的定义移到main 之外的顶层并将print 替换为println 是可行的。
  • @0dB,是的,我尝试将它们移动到顶层并编译程序并且所有三个值都是正确的。但是print 确实打印了一些东西,虽然不是它自己的东西。
  • 另一个有趣的效果:当我第一次加载修改后的程序(six 在顶层等)并在 REPL 中第一次运行println (unch six),我得到866(我有看到更长的数字),我第二次得到6。但是,这种行为并不一致,:reset 有时会直接产生6
  • 注册。 print 为你工作(对我来说没有输出),也许你和我有不同的弗雷格版本?我有 3.23.450-gf5b1730。
  • 貌似前两个prints的输出没有被flush,最后一个printlnflush了输出流。

标签: frege


【解决方案1】:

这是对 let 绑定变量的类型进行泛化确实会产生影响的罕见情况之一。

关键是,在这方面,弗雷格的行为与 GHC 类似,带有 pragma -XMonoLocalBinds,有关详细信息,请参见此处:https://github.com/Frege/frege/wiki/GHC-Language-Options-vs.-Frege#Let-Generalization 和此处:https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/other-type-extensions.html#typing-binds(还有一个指向 SPJ 论文的链接,它解释了基本原理)

简而言之,这意味着所有未注释的 let 绑定的变量都将具有 单态 类型,并且不能用于不同的类型。要恢复多态性,需要显式类型签名。

要让你的程序编译通过,在seven的绑定上加注解就足够了

seven :: Church a

关于 print/println:前者不刷新输出。所以你在 REPL 中有:

frege> print 'a'
IO ()
frege> print 'b'
IO ()
frege> println "dammit!"
abdammit!
IO ()

【讨论】:

  • 今天早上我有一种预感,实际上是在玩注解——我想我试过do let seven = (ch 7 :: Church Int)——所以,很高兴看到它是如何正确完成的,而且,很高兴知道这不是一个错误,这是一个功能:) 好的,打印不刷新,这解释了它(@Lech 也指出)。
  • 嗯,Church Int 是编译器 认为 应该是 seven 的类型(来自 unchr eight 的使用)。但这不适用于pre 中预期的函数类型。
猜你喜欢
  • 1970-01-01
  • 2012-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-22
  • 1970-01-01
  • 2021-11-27
相关资源
最近更新 更多