Haskell - All functions of the form A & # 8594; A -> ... & # 8594; A

I have a type (call it A), and I want to create a class of functions of type A β†’ A, A β†’ A β†’ A, A β†’ A β†’ A β†’ ... etc. This does not work:

{-# LANGUAGE FlexibleInstances #-} data A = A class AsToA a where takeA :: AsToA b => a -> A -> Either A b instance AsToA (A -> A) where takeA fa = Left (fa) instance AsToA b => AsToA (A -> b) where takeA fa = Right (fa) 

The following error message appears:

 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 '(fa)' In the expression: Right (fa) 

Any ideas? Thanks so much for any advice.

+6
source share
2 answers

As mentioned in the comments to another answer, you may not need Either , and takeA is basically always id , only with a type constraint. If so, you can make this class without methods:

 {-# 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 may need to convert functions to a generic type that allows you to dynamically pass A If so, Either will not be enough, but you can define your own:

 {-# 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 fa = Result (fa) instance AsToA (A -> b) => AsToA (A -> (A -> b)) where takeA fa = MoreArgs (takeA $ fa) 
+2
source

There is some confusion between the two b s:

 class AsToA a where takeA :: AsToA b => a -> A -> Either A b instance AsToA b => AsToA (A -> b) where takeA fa = Right (fa) 

This is not the same thing. Rename the first item to c

 class AsToA a where takeA :: AsToA c => a -> A -> Either A c instance AsToA b => AsToA (A -> b) where takeA fa = Right (fa) 

Right (fa) is now of type Either A b , but must be of type Either A c for any c for which AsToA c is executed. This does not check type.

The problem is that the signature

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

promises that takeA can return Either A c for any c that selects the caller. I think this is not what you want.


I'm still not sure what constitutes the real target result, but I think the problem is similar to the following.

For a function f type A->A->...->A returns a function \x -> fxx ... , with one application of x for each -> in type (hence, of type A->A ).

Possible Solution:

 {-# 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 (fx) x 

Note that this requires OverlappingInstances , which is pretty evil. I would recommend avoiding this.

To avoid this, in this case it is enough to define an instance even for type A

 {-# LANGUAGE FlexibleInstances #-} data A = A -- could be anything class C f where takeA :: f -> A -> A instance CA where takeA a = \_ -> a instance C b => C (A -> b) where takeA f = \x -> takeA (fx) x 
+4
source

All Articles