如何在Haskell中部分定义函数签名?

初始点:

fn :: [a] -> Int
fn = (2 *) . length

假设我们只想限制返回值,那么我们可以这样写:

fn list = (2 * length list) :: Int

如何限制只有论点? 简单。

fn list = 2 * length (list :: [Char])

虽然这是有效的,但最好将顶部的签名收集起来,而不是散布在函数体的周围。

这是我能接近的最接近的:

fnSig = undefined :: [Char] -> a
fn | False = fnSig
   | True  = (* 2) . length

基于http://okmij.org/ftp/Haskell/partial-signatures.lhs通过http://okmij.org/ftp/Haskell/types.html#partial-sigs

不过,我想要一个更清洁的解决方案。 更好的沟通,我的意图是部分限制。 像这样的东西,例如:

fn :: [Char] -> a
fn = (2 *) . length

或者可能:

fn :: [Char] -> _
fn = (2 *) . length

这可能吗?

编辑进一步说明:

@GaneshSittampalam在下面的评论中提到了一个重要的观点。 我正在寻找“完全没有类型签名的中间房屋,而且必须提供一个精确的房子”。 所以,我不是在寻找一个基于TypeClass的答案,我只是希望GHC填写我的函数的未指定(或未完全限制)类型的空白。

编辑回复@WillNess

是的,像这样的...

fn list = 2 * length list
  where
    _ = list :: [Char]

...可以工作,但只能用于参数,并且只有在函数不是无点的时候。 有没有办法将这种技术应用于无点函数或返回值?

编辑回复@Rhymoid

我得到了启发,并且用@ Rhymoid的想法进行了游戏,并提出了这个想法:

fn = (2 *) . length
  where
    _ = fn `asTypeOf` (undefined :: [Char] -> a)
    _ = fn `asTypeOf` (undefined :: a -> Int)
    _ = fn `asTypeOf` (undefined :: a -> b)
    _ = fn `asTypeOf` (undefined :: a)

这种方法还会限制fn的类型签名,并且不会污染任何名称空间。

通常我们只有一个asTypeOf行,我只是添加了多个来展示这种方法的强大程度。

它比我想要的更笨拙,但我认为它非常简洁,即使没有语言的特定语法支持,我们也可以做到这一点。

@Rymoid,如果你也喜欢,请将它添加到你的答案中。 :)


对于自我推销很抱歉,但这个特点正是博士最近发表的论文的主题。 学生Thomas Winant,我自己,Frank Piessens和Tom Schrijvers,最近由Thomas在2014年PADL研讨会上发表。 看到这里的全文。 这是一个已经存在于其他语言中的功能,但与Haskell GADT等功能的交互使得它足够有趣,可以计算出细节。

Thomas正在研究GHC的实施。 自文件撰写以来,它进一步改进,但在GHC中实施“通配约束”在技术上比我们预期的要难一些。 我们希望能够进一步开展工作并与GHC开发者联系以获得通过,但是否发生这种情况可能取决于有多少人希望在Haskell中具有此功能。

更新14-4-2015:经过Thomas的大量工作以及SPJ和其他GHC人员的意见后,部分类型签名已在GHC 7.10中发布。 Thomas Winant写了一篇关于如何使用它们的介绍性博客文章。


我一直在寻找一种方式来说' x '类型与T '相结合。 Will Ness和chi提供的解决方案与我所提出的解决方案非常接近,但是在Haskell 98中有一种方法可以实现,而不会屠杀你自己的功能。

-- Your function, without type signature.
fn = (2 *) . length

-- The type signature, without actual definition.
fnTy :: [Char] -> a
fnTy = undefined

-- If this type checks, then the type of 'fn' can be unified 
--                                      with the type of 'fnTy'.
fn_unifies_with_type :: ()
fn_unifies_with_type = let _ = fn `asTypeOf` fnTy in ()

你甚至可以去

fn = (2 *) . length
  where
    _ = fn `asTypeOf` (undefined :: [Char] -> a)

你正在寻找我们中许多人会喜欢的功能,但是Haskell没有这个功能。 也不是ghc。 你想要一种部分类型的签名。 为此建议的符号是

fn :: [Char] -> _
fn = (2*) . length

_这里的意思是“这里有一种类型,但我不能把它写出来”。

它看起来像一个非常简单的功能来实现(在签名中实例化具有统一变量的_ ),但没有人打算解决语义细节和与其他功能的交互。

链接地址: http://www.djcxy.com/p/7447.html

上一篇: How to define function signatures partially in Haskell?

下一篇: Test if a value has been evaluated to weak head normal form