2015-10-14 7 views
6

У меня есть тип (назовите его A), и я хочу создать класс функций типа A -> A, A -> A -> A, A -> A -> A -> ... и т.д. Это не работает:Haskell - Все функции формы 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) 

Любые идеи? Большое спасибо за любые советы.

+0

Я 90% уверен, что это потому, что 'takeA' неявно экзистенциально количественно. –

ответ

2

Как уже упоминалось в комментариях к другой ответ, вы не могли бы действительно нужен 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 s динамически.Если это так 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) 
+0

Этот второй ответ прекрасен, спасибо очень. Простите, если раньше я не был очень ясен. – RhubarbAndC

4

Существуют некоторая путаница между двумя 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 (f a) имеет тип Either A b но должен иметь тип Either A c для любого c такой, что AsToA c держит. Это не проверяет тип.

Вопрос здесь заключается в том, что подпись

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

обещает, что takeA может вернуться Either A c для любойc, выбор абонента. Думаю, это не то, что вы хотите.


Я все еще не уверен, что представляет собой фактический предполагаемый результат, но я думаю, что проблема аналогична следующей.

Учитывая функцию f типа A->A->...->A возвращает функцию \x -> f x x ..., с одним применением 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 
+1

* обещает, что takeA может возвращать A или A c для любого c * - поэтому, по существу, проблема 'takeA' объявляется как' forall b. AsToA b = a -> a -> Либо A b', где 'b' в этом случае является жестким, так? –

+0

Итак, что вы предлагаете мне делать? Можно ли вообще определить эту модель? – RhubarbAndC

+1

@RhubarbAndC Я не уверен, что вам нужно, '' Либо' для –

Смежные вопросы