具有记录更新语法的模糊def

时间:2015-12-23 00:09:10

标签: haskell

示例:

data Foo a
   = Foo { fooId :: a
         , fooName :: String
         , fooCount :: Int
         }

instance Default a => Default (Foo a) where
  def = Foo
    { fooId = def
    , fooName = "foo"
    , fooCount = 0
    }

-- this is ok
x :: Foo Int
x = def { fooName = "good" }

-- error, type of def is ambiguous (a could be anything with a Default instance)
y :: Foo Int
y = def { fooId = 2 }

-- ok again
z :: Foo Int
z = (def :: Foo Int) { fooId = 2 }

我想我明白为什么它是暧昧的。这不是问题。想象:

fooList :: [Foo Int]
fooList =
  [ (def :: Foo Int) { fooId = 0, fooName = "one" }
  , (def :: Foo Int) { fooId = 1 }
  , (def :: Foo Int) { fooId = 2, fooName = "three", fooCount = 42 }
  ...
  ]

相反,我想写:

fooList :: [Foo Int]
fooList =
  [ def { fooId = 0, fooName = "one" }
  , def { fooId = 1 }
  , def { fooId = 2, fooName = "three", fooCount = 42 }
  ...
  ]

在这种情况下,GHC如何推断def的类型是否有效?对于我关心的所有人来说可能是Foo (Maybe SomethingReallyCrazy)。我当时正在覆盖它Foo Int(或者它必须是那个开头)。

我想定义:

defFoo :: Foo Int
defFoo = def

将是一种解决方法,但......它很难看。有没有更好的方法呢?我缺少一些语言扩展?

1 个答案:

答案 0 :(得分:2)

看来你已经找到了问题的根源。之后剩下的就是美学。

我能理解对另一种全球约束的偏见。当地人怎么样?

fooList :: [Foo Int]
fooList = let def = Data.Default.Class.def :: Foo Int in
  [ def { fooId = 0, fooName = "one" }
  , def { fooId = 1 }
  , def { fooId = 2, fooName = "three", fooCount = 42 }
  ...
  ]

如果你愿意放弃def作为唱片名称,你可以减少一点尴尬:

fooList :: [Foo Int]
fooList = let d = def :: Foo Int in
  [ d { fooId = 0, fooName = "one" }
  , d { fooId = 1 }
  , d { fooId = 2, fooName = "three", fooCount = 42 }
  ...
  ]

至于这个

  

在这种情况下,GHC如何推断def的类型是否有效?

确实如此!假设某人还在另一个文件中定义了这个:

 data MyCustomDataType = Mwahahaha -- note, has no `Default` instance
 instance Default (Foo MyCustomDataType) where
   def = Foo
     { fooId = Mwahahaha
     , fooName = "bar"
     , fooCount = 3
     }

并将其与已编译的代码相关联。类型类实例是全局的(“开放世界”假设),因此它们的实例可用于您的代码。

现在,当某些def :: Foo a被赋予a时,有两种可能性:

  • Default a,暗示fooName def == "foo"
  • a ~ MyCustomDataType,暗示fooName def == "bar"

这是一个无法解决的歧义。

如果你想要关闭这个世界 - 防止引入这样的歧义,你必须告诉ghc 如何