简体   繁体   English

Haskell - 形式A的所有函数 - > A - > ... - > A.

[英]Haskell - All functions of form A -> A -> … -> A

I have a type (call it A) and I want to make a typeclass of the functions of type A -> A, A -> A -> A, A -> A -> A -> ... etc. This doesn't work: 我有一个类型(称之为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)

I get the following error message: 我收到以下错误消息:

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)

Any ideas? 有任何想法吗? Thanks very much for any advice. 非常感谢任何建议。

There is some confusion between the two b s: 两个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)

These are not the same. 这些都不一样。 Let's rename the first one to c 让我们将第一个重命名为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)

Now, Right (fa) has type Either A b but should have type Either A c for any c such that AsToA c holds. 现在, Right (fa)类型为Either A b但应该具有类型Either A c任何c Either A c ,以便AsToA c成立。 This does not type check. 这不是类型检查。

The issue here is that the signature 这里的问题是签名

  takeA :: AsToA c => a -> A -> Either A c

promises that takeA can return Either A c for any c , caller's choice. 承诺, takeA可以返回Either A c 任何 c ,来电者的选择。 This is not what you want, I guess. 我想这不是你想要的。


I'm still not sure about what the actual intended result is, but I guess the problem is similar to the following one. 我仍然不确定实际的预期结果是什么,但我猜这个问题类似于下面的问题。

Given a function f of type A->A->...->A return a function \\x -> fxx ... , with one application of x for each -> in the type (hence of type A->A ). 给定类型为A->A->...->A的函数f A->A->...->A返回一个函数\\x -> fxx ... ,每个应用一个x ->类型(因此类型A->A )。

A possible solution is 可能的解决方案是

{-# 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

Note that this requires OverlappingInstances to be used, which is quite evil . 请注意,这需要使用OverlappingInstances ,这是非常邪恶的 I'd recommend to avoid it. 我建议避免它。

To avoid it, in this case it's enough to define an instance even for the type A . 为了避免这种情况,在这种情况下,甚至为类型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

As mentioned in the comments to the other answer, you might not really need the Either , and takeA is then basically always id , just with a type restriction. 正如对其他答案的评论中所提到的,你可能并不真的需要Either ,而takeA则基本上都是id ,只是带有类型限制。 If so you can make this a method-less class: 如果是这样,你可以把它变成一个无方法的类:

{-# 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))

Alternatively, you might want to convert the functions to a common type that allows you to pass in A s dynamically. 或者,您可能希望将函数转换为允许您动态传入A的公共类型。 If so Either won't be enough, but you can define your own: 如果是这样, 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM