Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - All functions of form A -> A -> ... -> A

Tags:

haskell

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:

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

like image 670
RhubarbAndC Avatar asked Oct 14 '15 08:10

RhubarbAndC


People also ask

What does -> mean in Haskell?

(->) is often called the "function arrow" or "function type constructor", and while it does have some special syntax, there's not that much special about it. It's essentially an infix type operator. Give it two types, and it gives you the type of functions between those types.

What are Haskell functions?

Haskell is a pure functional language. This means functions in Haskell behave closer to mathematical functions. A function operates on the input parameters and returns a result. Functions do not modify state.

What are function types in Haskell?

Haskell has first-class functions : functions are values just like integers, lists, etc. They can be passed as arguments, assigned names, etc. … val is value of type Int , and half_of is a value of type Float -> Float .

What does int -> int mean Haskell?

It states that this function is of type Int -> Int , that is to say, it takes an integer as its argument and it returns an integer as its value.


2 Answers

There is some confusion between the two bs:

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

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 (f a) has type Either A b but should have type Either A c for any c such that AsToA c holds. 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. 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 -> f x x ..., with one application of x for each -> in the type (hence of type 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. I'd recommend to avoid it.

To avoid it, in this case it's enough to define an instance even for the type 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
like image 176
chi Avatar answered Oct 19 '22 06:10

chi


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. 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 As dynamically. If so Either won't 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 f a = Result (f a)

instance AsToA (A -> b) => AsToA (A -> (A -> b)) where
    takeA f a = MoreArgs (takeA $ f a)
like image 31
Ørjan Johansen Avatar answered Oct 19 '22 05:10

Ørjan Johansen