【发布时间】:2015-12-04 17:11:44
【问题描述】:
我正在学习 Haskell,但遇到了一个我似乎无法解决的问题。基本上,我的用例如下。我正在处理一个字符串;如果它以" 字符开头,那么我想将它作为字符串返回(剥离");否则,我想在上面返回read 的结果。换句话说:
parse "\"foo\"" -> "foo"
parse "3" -> 3
parse "1.5" -> 1.5
到目前为止,我已经尝试了以下方法。
- 多态返回类型
parse :: String -> a
parse ('"':xs) = init xs -- strip closing '"'
parse string = read string
这会产生编译时错误Couldn't match expected type `a' with actual type `[Char]'。 a 不应该匹配任何类型,包括像 [Char] 这样的复杂类型?
- 类型类
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
class Parse where parse :: String -> a
instance Read a => Parse a where parse = read
instance Parse String where parse = init . tail
这会编译,但会出现以下运行时错误:
Overlapping instances for Parse a0 arising from a use of `parse'
Matching instances:
instance Read a => Parse a -- Defined at parse.hs:5:14
instance Parse [Char] -- Defined at parse.hs:7:14
(The choice depends on the instantiation of `a0'
To pick the first instance above, use -XIncoherentInstances
when compiling the other instance declarations)
String 不是Read 的实例,所以我不太确定它在哪里看到了重叠。
顺便说一句,编译指示在那里,否则我会得到编译时错误:
Illegal instance declaration for `Parse [Char]'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Parse [Char]'
和
Constraint is no smaller than the instance head
in the constraint: Read a
(Use -XUndecidableInstances to permit this)
In the instance declaration for `Parse a'
- 使
String成为Read的实例
我不确定如何执行此操作,文档对我来说也不是很清楚。不过,如果我能弄清楚,听起来这可能是正确的做法。但是一个问题一直萦绕在我的脑海中:如果我在一个模块中将String 设为Read 的实例,那么即使我不导出相关位,这是否会更改整个应用程序的类?如果是这样,那么我不确定我是否喜欢它的含义。
这就是我到目前为止所尝试的。我的方法错了吗?基本上是正确的,我只需要修复几个细节吗?请告诉我。
【问题讨论】:
-
看起来您想要一个依赖类型的函数,因为返回类型取决于其参数的值。你实际上想做什么,因为这通常意味着你做错了事?
-
@bheklilr:我正在尝试完全按照我所说的去做:将字符串解析为未知类型的值,这与
read函数所做的非常相似。为什么你认为这是错误的方式?如果是错误的方式,那么正确的方式是什么? -
你希望使用这个函数的代码是什么样的?调用这个函数后不知道发生了什么事情有用吗?用
Either怎么样? -
read不会将值解析为未知类型。尝试在 GHCi 中输入read "1234"。它不起作用,是吗?现在输入read "1234" :: Int,这是有效的,因为您已经告诉read要返回什么类型。并不是read决定返回类型,你必须在调用它之前从read确定你想要的返回类型。如果您没有指定显式签名并且它仍然可以编译,这是因为 GHC 使用类型推断来确定应该去那里的类型,但归根结底read并没有确定它的返回类型。 -
@MarnenLaibow-Koser
read仍然在编译时确定其类型。这就是为什么我说为了编译 GHC 将确定那里需要的类型,但它始终是调用者确定的多态性,而不是被调用者。
标签: haskell