初始点:
fn :: [a] -> Int
fn = (2 *) . length
Run Code Online (Sandbox Code Playgroud)
比方说,我们只是想约束的返回值,那么我们可以这样写:
fn list = (2 * length list) :: Int
Run Code Online (Sandbox Code Playgroud)
如何仅限制参数?简单.
fn list = 2 * length (list :: [Char])
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但最好是收集顶部的签名而不是散布在函数体周围.
这是我能得到的最接近的:
fnSig = undefined :: [Char] -> a
fn | False = fnSig
| True = (* 2) . length
Run Code Online (Sandbox Code Playgroud)
基于http://okmij.org/ftp/Haskell/partial-signatures.lhs通过http://okmij.org/ftp/Haskell/types.html#partial-sigs
但是,我想要一个更清洁的解决方案.更好地沟通的东西,我的意图是部分限制.像这样的东西,例如:
fn :: [Char] -> a
fn = (2 *) . length
Run Code Online (Sandbox Code Playgroud)
或者可能:
fn :: [Char] -> _
fn = (2 *) . length
Run Code Online (Sandbox Code Playgroud)
这可能吗?
@GaneshSittampalam在下面的评论中提到了一个重点.我正在寻找"在没有任何类型的签名和必须给出一个精确的签名之间的中间房子".所以,我不是在寻找基于TypeClass的答案,我只是希望GHC填写我的函数的未指定(或不完全受限)类型的空白.
是的,像这样......
fn list = 2 * length list
where
_ = list :: [Char]
Run Code Online (Sandbox Code Playgroud)
...可以工作,但仅适用于参数,并且只有在函数不是无点的情况下才有效.有没有办法将此技术应用于无点函数或返回值?
我受到了启发,并在@ Rhymoid的想法中玩弄了一下,然后想出了这个:
fn = (2 *) . length
where
_ = fn `asTypeOf` (undefined :: [Char] -> a)
_ = fn `asTypeOf` (undefined :: a -> Int)
_ = fn `asTypeOf` (undefined :: a -> b)
_ = fn `asTypeOf` (undefined :: a)
Run Code Online (Sandbox Code Playgroud)
此方法还限制fn的类型签名,并且不会污染任何名称空间.
通常我们只有一条asTypeOf
线,我只是添加了多条线来展示这种方法有多强大.
它比我想要的更笨拙,但我想即使没有语言的特定语法支持,我们也可以做到这一点.
@Rhymoid,如果您也喜欢,请将其添加到您的答案中.:)
Dom*_*ese 36
对于自我推销感到抱歉,但正是这个特色是博士最近的一篇论文的主题.学生Thomas Winant,我自己,Frank Piessens和Tom Schrijvers,最近由Thomas在2014年PADL研讨会上发表.请参阅此处查看完整的论文.这是一种已经存在于其他语言中的功能,但与Haskell GADT等功能的交互使其足够有趣,可以解决细节问题.
托马斯正致力于GHC的实施.自撰写论文以来,它已得到进一步改进,但在GHC中实施"通配符约束"在技术上比我们预期的要困难一些.我们希望能够进一步开展工作并与GHC开发人员联系以获得它,但是否这种情况发生可能取决于人们希望在Haskell中拥有该功能的程度......
更新14-4-2015:经过Thomas的大量工作以及SPJ和其他GHC人员的意见,GHC 7.10中已发布部分类型签名.Thomas Winant撰写了一篇关于如何使用它们的介绍性博客文章.
小智 13
我一直在寻找一种方式来说' 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 ()
Run Code Online (Sandbox Code Playgroud)
你甚至可以去做
fn = (2 *) . length
where
_ = fn `asTypeOf` (undefined :: [Char] -> a)
Run Code Online (Sandbox Code Playgroud)
aug*_*tss 10
你正在寻找我们很多人都想要的功能,但Haskell没有.也不是.你想要一种部分类型的签名.建议的符号是
fn :: [Char] -> _
fn = (2*) . length
Run Code Online (Sandbox Code Playgroud)
当_
意思是"这里有一个类型,但我也懒得写出来".
它看起来像是一个非常容易实现的功能(_
在签名中使用统一变量进行实例化),但是没有人愿意计算出语义细节以及与其他功能的交互.
要仅指定参数的类型,您可以编写类似的内容
fn list = 2 * length list
where
a :: [Char]
a = list `asTypeOf` a
Run Code Online (Sandbox Code Playgroud)
因此,以后很容易修改它,例如,
fn list = 2 * fromIntegral (length list)
where
a :: [Char]
a = list `asTypeOf` a
Run Code Online (Sandbox Code Playgroud)
并相应地改变其推断类型:
*Main> :t fn
fn :: [Char] -> Int
*Main> :r
-- changed file reloaded
*Main> :t fn
fn :: (Num t) => [Char] -> t
Run Code Online (Sandbox Code Playgroud)
您可以使用相同的扭曲技术来指定函数的返回类型,可能以无点样式定义,但这并不漂亮.
fn2 list = r
where
r :: Int
r = f list
f = (2 *) . length
Run Code Online (Sandbox Code Playgroud)
它与您现在拥有的内容没有太大差别,只需将代码和类型规范分开.