这不会键入检查:
module DoesntTypeCheck where {
import Prelude(Either(..));
defaultEither :: a -> Either b c -> Either a c;
defaultEither a (Left _) = Left a;
defaultEither _ b = b;
}
但是这样做:
module DoesTypeCheck where {
import Prelude(Either(..));
defaultEither :: a -> Either b c -> Either a c;
defaultEither a (Left _) = Left a;
defaultEither _ (Right b) = Right b;
}
编译器可能有错误,Either a c
类型只能是Left (x::a)
或Right (y::c)
,如果不是Left
,则是Right
,我们知道Right :: b -> Either a b
也是Right (y::c) :: Either a c
。
答案 0 :(得分:9)
问题是,当你说
defaultEither _ b = b
您是说输出值b
与第二个输入值相同。只有这些值具有相同的类型,才有可能。但是您已经告诉编译器,输入的类型为Either b c
,而输出的类型为Either a c
。这些是不同的类型,所以难怪编译器会抱怨。
我了解您正在尝试做的事情-但是即使一个值Right x
(类型为x
的{{1}}可以是c
类型的任何Either d c
的类型签名都会将输入和输出值限制为具有不同d
的版本。这意味着您不能使用相同的变量来引用两个值。
答案 1 :(得分:5)
让我们尝试一个更简单的示例:
data Foo x = Bar
foobar :: Foo a -> Foo b
foobar f = f
看看Foo
的定义。左侧有一个类型变量(x
),它实际上从未出现在右侧的任何地方。这是所谓的“幻像类型变量”的示例。类型签名中有一个类型实际上与实际值中的任何类型都不对应。 (顺便说一下,这是完全合法的。)
现在,如果您有表达式Just True
,则从True :: Bool
开始,然后是Just True :: Maybe True
。但是,表达式Nothing
绝对是Maybe
某物。但是,在没有实际价值存在的情况下,没有什么可以强迫它成为任何特定的可能类型。在这种情况下,类型变量是幻影。
我们这里有类似的事情; Bar :: Foo x
,用于任何x
。因此,您会认为我们对foobar
的定义是合法的。
然后您会错误。
即使期望值Foo a
的类型为Foo b
,也不能传递Foo Int
的值,即使它们具有完全相同的运行时结构。因为类型检查器不关心运行时结构;它只关心类型。就类型检查器而言,Foo Bool
与foobar :: Foo a -> Foo b
foobar Bar = Bar
不同,即使在运行时没有明显的区别。
那是您的代码被拒绝的原因。
事实上,你必须写
Bar
让类型检查器知道您输出的Bar
是一个新的 Foo Int
,而不是您收到的输入(因此它可以具有另一种类型。
信不信由你,这实际上是一个功能,而不是一个错误。您可以编写使之生效的代码,以使Foo Char
的行为不同于Bar
。即使在运行时它们都只是b
。
您已经发现,解决方案是从Right
中取出ValueError: Error when checking target:
expected dropout_5 to have shape (33,) but got array with shape (1,).
的值,然后立即重新输入。看起来毫无意义而且很愚蠢,但是它是要明确通知类型检查器类型可能已更改。这也许很烦人,但这只是该语言的那些角落之一。这不是一个错误,它是专门设计用于这种方式的。
答案 2 :(得分:3)
一个c类型只能是...
确实,但是在您的第一个示例中,值fatal: bad config line 30 in file [path]/.gitconfig
的类型不是b
!正如您的类型签名所证明的,它具有类型Either a c
。当然,您不能在期望Either b c
的地方返回Either b c
。相反,您必须对值进行解构并使用正确的类型对其进行重构。
答案 3 :(得分:0)
一个ac类型只能是Left(x :: a)或Right(y :: c),如果不是Left则它是Right,我们知道Right :: b-> ab都是右(y :: c)::要么是c。
我认为您正在将type
构造函数与data
构造函数混淆。 Either
在ghc-base
中的定义如下:
data Either a b = Left a | Right b
Either
是具有两个抽象变量的type
构造函数。即采用两种类型(Int
,String
等)。并构造一个像Either Int String
这样的具体类型。
Left
和Right
是data
的构造函数。它们采用1
,"hi"
之类的实际值,并构造Left 1
和Right "hi"
之类的值。
Prelude> :t Left
Left :: a -> Either a b
Prelude> :t Right
Right :: b -> Either a b
Haskell类型推断不能与values
(Left
和Right
)一起使用。它仅适用于types
(Either
)。因此,类型检查器仅了解Either b c
和Either a c
-因此,在第一种情况下,变量不匹配。