我有两个类型类
class Concatable a where
empty :: a
(<+>) :: a -> a -> a
class Concatable b => Output a b where
out :: a -> b
Run Code Online (Sandbox Code Playgroud)
和以下功能
nl :: (Output a AnsiDark) => [a] -> AnsiDark
nl a = foldr addNl empty a
where
addNl :: a -> AnsiDark -> AnsiDark
addNl ast org = doAddIf ast <+> org
doAddIf :: a -> AnsiDark
doAddIf ast = if out ast == sDedent
then out ast
else out ast <+> sNewline
Run Code Online (Sandbox Code Playgroud)
(AnsiDark实现Concatable,sDedent是类型的常量AnsiDark)
以及启用的以下语言扩展(可能甚至与问题无关,对于这些与复杂类型有关的问题,我还是很陌生)
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
../src-hs/ANSITerm.hs:65:22: error:
• Could not deduce (Output a1 AnsiDark) arising from a use of ‘out’
from the context: Output a AnsiDark
bound by the type signature for:
nl :: forall a. Output a AnsiDark => [a] -> AnsiDark
at ../src-hs/ANSITerm.hs:59:1-44
• In the first argument of ‘(==)’, namely ‘out ast’
In the expression: out ast == sDedent
In the expression:
if out ast == sDedent then out ast else out ast <+> sNewline
Run Code Online (Sandbox Code Playgroud)
我不太明白为什么haskell无法推断出a……我本来会out像这样使用类型注释
out @a @AnsiDark
Run Code Online (Sandbox Code Playgroud)
但类型注释似乎不适用于类型变量。所以...我的问题到底在哪里?我该如何解决呢?
nl :: (Output a AnsiDark) => [a] -> AnsiDark
...
where
doAddIf :: a -> AnsiDark
...
Run Code Online (Sandbox Code Playgroud)
a这两行中出现的s 不相同。好像您已经写过:
nl :: (Output x AnsiDark) => [x] -> AnsiDark
...
where
doAddIf :: y -> AnsiDark
...
Run Code Online (Sandbox Code Playgroud)
由于您正在使用out,因此doAddif需要Output向其签名添加约束(我相信如果删除签名,它将起作用,因为将推断出正确的签名)。
您可能也对该ScopedTypeVariables扩展感兴趣。启用此功能后,如果您编写
nl :: forall a. (Output a AnsiDark) => [a] -> AnsiDark
Run Code Online (Sandbox Code Playgroud)
那么您可以在子句的签名以及您尝试过的类型应用程序中引用它 。awhereout @a @AnsiDark