我正在编写我自己的Writer monad版本,以进行自我教育。我试图有一些普遍性(但不是试图通过静态解析的类型参数或其他解决方法完全实现/方法)。F#静态成员,缺少泛型类型的实例 - 可能的错误?
我的第一个版本得到一个警告:
type Writer<'w, 'a> = | Writer of 'a * List<'w> with
static member sum (l1:'w list) (l2: 'w list) = l1 @ l2
[<AutoOpen>]
module WriterMonadMod =
module Writer =
let apply (mf:Writer<'w, ('a -> 'b)>) (ma:Writer<'w, 'a>) : Writer<'w, 'b> =
let (Writer (f, l1)), (Writer (a, l2)) = (mf, ma)
let b = f a
Writer (b, Writer.sum l1 l2) // Warning, on "Writer.sum",
//Instantiation of generic type missing, can't be inferred.
好吧,这是有道理的。我们需要哪一个静态总和?对于哪些特定的实例类型的Writer?我不知道我是否可以忽略这个警告,或者最终是否可以咬我。所以我尝试“的.sum”之前把一个类型参数上的“作家” - 但现在,导致错误:
Writer (b, Writer<'w, 'b>.sum l1 l2) //Error, on "<'w, 'b>",
//unexpected type arguments.
这让我困惑,因为它看起来像在其他的语法,这样回答Why can't F# infer the type in this case?(Cell<float>.Create 1.0
;它适用于我,没有错误,没有警告;并尝试非泛型类型不会改变我的问题。)
所以我愚弄名称,区分类型从它的值构造函数,添加“T”现在修复它自己!:
type WriterT<'w, 'a> = | Writer of 'a * List<'w> with
//...
static member sum (l1:'w list) (l2: 'w list) = l1 @ l2
[<AutoOpen>]
module WriterMonadMod =
module WriterT =
let apply (mf:WriterT<'w, ('a -> 'b)>) (ma:WriterT<'w, 'a>) : WriterT<'w, 'b> =
let (Writer (f, l1)), (Writer (a, l2)) = (mf, ma)
let b = f a
Writer (b, WriterT<'w, 'b>.sum l1 l2) //No warning, no error.
//(With "T" distinguishing the type name from value constructor.)
Does th是有道理的?为什么很明显,在类型和构造函数中使用相同名称的通常做法似乎在这里引起歧义?
(旁注:“T”是不是一个伟大的选择,我想,因为这不是一个单子转换而对于上应用的所有类型注释的原因是调试。)
更新因托马斯的回答:
奇怪的是,对我来说,这也可以避免错误和警告。 Whildcards发球解决歧义警告!
module WriterT =
let apply (mf:WriterT<_,_>) (ma:WriterT<_,_>) : WriterT<_,_> =
let (Writer (f, log1)), (Writer (a, log2)) = (mf, ma)
let b = f a
Writer (b, WriterT<_,_>.sum log1 log2)
谢谢你看Tomas。我想我应该提交一个建议。这对我来说似乎是一个很好的机会,可以亲自尝试查看编译器,看看我是否可以自己调试,我一直在努力学习。 – RomnieEE
现在,它在我的代码中引起了我的注意:无法推断静态“.sum”的Writer类型的警告消失了_wild card_ type注释!我发现在'apply'中将'WriterT'上的所有类型参数更改为'<_,_>'仍然可以避免这种警告。似乎很奇怪,通配符可以修复模糊性。但也许这是因为我不太了解类型推断是如何工作的。 – RomnieEE