【发布时间】:2014-02-09 11:23:37
【问题描述】:
起点:
fn :: [a] -> Int
fn = (2 *) . length
假设我们只想要约束返回值,那么我们可以这样写:
fn list = (2 * length list) :: Int
限制 only 参数怎么样?很简单。
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 行之一,我只是添加了多个以展示这种方法的强大功能。
它比我想要的要笨拙一些,但我想它非常简洁,即使没有语言的特定语法支持,我们也可以做到这一点。
@Rhymoid,如果您也喜欢它,请将其添加到您的答案中。 :)
【问题讨论】:
-
Erm... 你可以在 Haskell 中很好地做到这一点,当然只有你需要合适的类型类约束和多态函数,否则它无法工作。但是考虑
fromInteger :: Num a => Integer -> a。 -
这只是在完全没有类型签名和必须给出一个精确的签名之间有一个中途的房子。您可以按照此问题中描述的方式在 F# 中使用 _。
-
@GaneshSittampalam 这正是我要找的! “在完全没有类型签名和必须给出精确的签名之间的中途之家”。
-
我看不出使用类型变量
a有什么问题——它是不限制任何类型,是吗?或者这只是显示不受限制的意图? -
@Bergi
fn :: [Char] -> a ; fn list = 2 * length listresults in compile error "无法将预期类型a与实际类型Int匹配 --a是受类型签名约束的刚性类型变量for fn"——意思是,因为我们声明了fn :: [Char] -> a,所以定义不能产生比user-given类型签名更窄的类型。编译器假设如果用户说a(即任何类型),他们是认真的。
标签: haskell