[英]Haskell - All functions of form A -> A -> … -> A
我有一个类型(称之为A),我想创建类型为A的函数的类型类 - > A,A - > A - > A,A - > A - > A - > ...等等工作:
{-# LANGUAGE FlexibleInstances #-}
data A = A
class AsToA a where
takeA :: AsToA b => a -> A -> Either A b
instance AsToA (A -> A) where
takeA f a = Left (f a)
instance AsToA b => AsToA (A -> b) where
takeA f a = Right (f a)
我收到以下错误消息:
AsToA.hs:12:22:
Couldn't match expected type ‘b1’ with actual type ‘b’
‘b’ is a rigid type variable bound by
the instance declaration at AsToA.hs:11:10
‘b1’ is a rigid type variable bound by
the type signature for
takeA :: AsToA b1 => (A -> b) -> A -> Either A b1
at AsToA.hs:12:3
Relevant bindings include
f :: A -> b (bound at AsToA.hs:12:9)
takeA :: (A -> b) -> A -> Either A b1 (bound at AsToA.hs:12:3)
In the first argument of ‘Right’, namely ‘(f a)’
In the expression: Right (f a)
有任何想法吗? 非常感谢任何建议。
两个b
之间存在一些混淆:
class AsToA a where
takeA :: AsToA b => a -> A -> Either A b
instance AsToA b => AsToA (A -> b) where
takeA f a = Right (f a)
这些都不一样。 让我们将第一个重命名为c
class AsToA a where
takeA :: AsToA c => a -> A -> Either A c
instance AsToA b => AsToA (A -> b) where
takeA f a = Right (f a)
现在, Right (fa)
类型为Either A b
但应该具有类型Either A c
任何c
Either A c
,以便AsToA c
成立。 这不是类型检查。
这里的问题是签名
takeA :: AsToA c => a -> A -> Either A c
承诺, takeA
可以返回Either A c
任何 c
,来电者的选择。 我想这不是你想要的。
我仍然不确定实际的预期结果是什么,但我猜这个问题类似于下面的问题。
给定类型为
A->A->...->A
的函数f
A->A->...->A
返回一个函数\\x -> fxx ...
,每个应用一个x
->
类型(因此类型A->A
)。
可能的解决方案是
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
data A = A -- could be anything
class C f where
takeA :: f -> A -> A
instance C (A -> A) where
takeA f = f
instance C b => C (A -> b) where
takeA f = \x -> takeA (f x) x
请注意,这需要使用OverlappingInstances
,这是非常邪恶的 。 我建议避免它。
为了避免这种情况,在这种情况下,甚至为类型A
定义一个实例也足够了。
{-# LANGUAGE FlexibleInstances #-}
data A = A -- could be anything
class C f where
takeA :: f -> A -> A
instance C A where
takeA a = \_ -> a
instance C b => C (A -> b) where
takeA f = \x -> takeA (f x) x
正如对其他答案的评论中所提到的,你可能并不真的需要Either
,而takeA
则基本上都是id
,只是带有类型限制。 如果是这样,你可以把它变成一个无方法的类:
{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}
data A = A
class AsToA a
takeA :: AsToA a => a -> a
takeA = id
instance AsToA (A -> A)
instance AsToA (A -> b) => AsToA (A -> (A -> b))
或者,您可能希望将函数转换为允许您动态传入A
的公共类型。 如果是这样, Either
不够,但你可以定义自己的:
{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}
data A = A
data R = Result A | MoreArgs (A -> R)
class AsToA a where
takeA :: a -> A -> R
instance AsToA (A -> A) where
takeA f a = Result (f a)
instance AsToA (A -> b) => AsToA (A -> (A -> b)) where
takeA f a = MoreArgs (takeA $ f a)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.