[英]Composing functions with a intermediate polymorphic type in Haskell
我有以下文件:
module SimpleComposition where
class Intermediate a where
f :: a -> Int
g :: Char -> a
h :: Char -> Int
h = f . g
尝试在 ghci 中加载它时,出现错误:
main.hs:8:5: error:
* No instance for (Intermediate a0) arising from a use of `f'
* In the first argument of `(.)', namely `f'
In the expression: f . g
In an equation for `h': h = f . g
|
8 | h = f . g
| ^
我认为问题在于有人可能会使用 2 种不同类型,它们是此组合中的Intermediate
实例。 当我导出这个模块时,我如何保证它是一样的?
PS:这是一个比我之前提出的问题更好的最小示例(如何在 Haskell 中组合多态函数? )。
问题不在于无法推断出实例,而是编译器确实无法知道您可能想要的类型。 g
可以产生任何向它询问的类型(前提是它有一个Intermediate
实例), f
可以使用任何这样的类型......但没有人指定哪一个。
但这很容易解决:现在只需 select 一个类型。 当然,它必须是有实例的; 例如,如果你有
instance Intermediate Char where
f = fromEnum
g = id
那么你可以使用
h :: Char -> Int
h = (f :: Char -> Int) . g
修复类型选择的更简洁的方法是使用语法扩展:
{-# LANGUAGE TypeApplications #-}
h = f @Char . g
...或者,为了强调您只是在中间固定类型,
h = f . id @Char . g
我认为问题在于有人可能会使用 2 种不同类型,它们是此组合中的中间实例。
没有问题是 Haskell 不能再从签名派生什么a
要使用。 假设有两种Intermediate
类型:
instance Intermediate Char where
# …
instance Intermediate Bool where
# …
现在h
有两种实现:
h :: Char -> Int
h = f . (g :: Char -> Char)
或者:
h :: Char -> Int
h = f . (g :: Char -> Bool)
可以使用无数种Intermediate
类型。 问题是 Haskell 无法根据类型签名判断使用什么类型。
我们可以给它一个类型提示,但这当然意味着中间类型是固定的。
解决此问题的一种简单方法是使用asTypeOf:: a -> a -> a
。 这基本上是一个const
function,但是两个参数具有相同的类型。 因此,这用于添加提示要使用什么类型,例如:
h :: Intermediate a => a -> Char -> Int
h a x = f (g x `asTypeOf` a)
因此,此处参数a
值并不重要,这是一种“注入”类型的方法,该类型将用作g
的结果和f
的参数的类型。
如果您以后使用h
,您可以使用:
h (undefined :: Char) 'a'
指定f
应该具有类型Char -> Char
,并且g
应该具有类型Char -> Int
。
就像@leftroundabout和@DanielWagner说的那样,不使用这种虚拟变量的更干净的解决方案是在签名中添加类型变量:
{-# LANGUAGE AllowAmbiguousTypes, ScopedTypeVariables, TypeApplications #-}
h :: forall a. Intermediate a => Char -> Int
h = f . g @ a
然后我们可以将h
与类型变量一起使用:
h @ Char 'a'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.