Haskell类型类混淆,无法推断推断的类型

时间:2019-04-11 10:40:57

标签: haskell

抱歉,每两年一次,我会以较小的方式涉足Haskell,然后我无法回避它。

最好只是做一个例子。

stream

所以,我想做的是创建数据类型,然后根据类中数据类型的成员身份定义两个函数。...

这可行。...

List<Employee> employees = ...;
List<Employee> employeesAfterUpdate = ListUtils.partition(employees, 20)
    .parallelStream()
    .peek(item -> updateAvailability(user, null, item))
    .flatMap(Collection::stream)
    .collect(Collectors.toList());

简单...

担心#1 ...如果删除x1和x2的类型声明,ghc会抱怨

> {-# LANGUAGE MultiParamTypeClasses #-}
> {-# LANGUAGE ScopedTypeVariables #-}
> {-# LANGUAGE AllowAmbiguousTypes #-}
> {-# LANGUAGE FlexibleInstances #-}
> {-# LANGUAGE FlexibleContexts #-}


> class Foo a b where
>     foo :: a -> b
>     
> class Bar a b where
>     bar :: a -> b

> data A a = A a
> data B b = B b

> instance Foo (A a) a where
>   foo (A a) = a

> instance Bar (B b) b where
>   bar (B b) = b

这很着急,不是很明显吗?……而这种事情将再次发生……。

如果我写

> f1 x = foo x
> f2 x = bar x

> x1 :: String
> x1 = f1 $ A "1"
> x2 :: String
> x2 = f2 $ B "1"

对我来说,这是完全合理的……ghc同意!

我问它的类型...我明白了

• Ambiguous type variable ‘b1’ arising from a use of ‘f1’
      prevents the constraint ‘(Foo (A [Char]) b1)’ from being solved.
      Relevant bindings include x1 :: b1 (bound at catdog.lhs:27:3)
      Probable fix: use a type annotation to specify what ‘b1’ should be.
      These potential instance exist:
        instance Foo (A a) a -- Defined at catdog.lhs:17:12
    • In the expression: f1 $ A "1"
      In an equation for ‘x1’: x1 = f1 $ A "1"
   |
27 | > x1 = f1 $ A "1"    |        ^^^^^^^^^^

我可以买。

像一个好的程序员一样,我将类型粘贴到

> f x = bar (foo x)

和“ BOOM” ...

f :: (Bar a1 b, Foo a2 a1) => a2 -> b

所以ghc告诉我它没有类型声明就推断出的类型,现在还不确定!

现在...我的头上通常有一个嵌齿轮,通过使用scala或f#或其他一些OO样式类型系统,它会向后转,我必须反过来....我发疯了吗?

1 个答案:

答案 0 :(得分:2)

让我们再次看看您的示例:

> class Foo a b where
>     foo :: a -> b

这里的问题是给定的a可能对应多个给定的b;例如,您可能同时拥有instance Foo Int Charinstance Foo Int Bool。这会导致您遇到的类型推断问题。

> f1 x = foo x
> f2 x = bar x

> x1 :: String
> x1 = f1 $ A "1"
> x2 :: String
> x2 = f2 $ B "1"

例如,在这里,您同时指定了ab,因此GHC知道您在谈论instance (A String) String。删除签名时,GHC不知道使用什么b。您尚未定义任何其他实例,也没有定义,但是GHC不知道。

那么我们如何解决这个问题?我们使用{-# LANGUAGE FunctionalDependencies #-}

> class Foo a b | a -> b where
>     foo :: a -> b

基本上,这告诉GHC,对于任何给定的a,只有一个对应的b。这样可以解决您的问题(尽管我承认我还没有测试过)。有关功能依赖性的更多信息,请参见this SO answer,它也解决了您的bar (foo x)问题。

相关问题