2015-01-10 3 views
3

Я хотел бы построить тип, который бы соответствовал бы чему угодно, но никогда не использовался.Haskell: Как построить гетерогенный тип Любой

Пример:

type Any = forall a. a 
f :: (x, Any) -> (Any, y) -> (x,y) 
f (x,_) (_,y) = (x,y) 

Это компилируется нормально с {-# LANGUAGE ImpredicativeTypes #-}, но если я пытаюсь

f ("hi", 2) (3, (1, 2)) 

Я получаю ошибку:

<interactive>:19:9: 
    No instance for (Num a) arising from the literal `2' 
    Possible fix: 
     add (Num a) to the context of a type expected by the context: a 
    In the expression: 2 
    In the first argument of `f', namely `("hi", 2)' 
    In the expression: f ("hi", 2) (3, (1, 2)) 

<interactive>:19:13: 
    No instance for (Num a) arising from the literal `3' 
    Possible fix: 
     add (Num a) to the context of a type expected by the context: a 
    In the expression: 3 
    In the second argument of `f', namely `(3, (1, 2))' 
    In the expression: f ("hi", 2) (3, (1, 2)) 

Что бы хорошо, если я просто хотел x и y, чтобы быть Num, но то, что я планирую сделать с этим, должно быть намного более гибким, чем это. Я понимаю, что forall a. a соответствует всем типам, но может передавать только тон, который никогда не может быть вычислен и снижен. Но у меня нет желания когда-либо заглядывать в «Любой».

+1

Почему вы не можете использовать другую переменную типа 'z' вместо' Any'? – chaosmasttter

+0

, потому что функция, которую я планирую использовать Any in, выглядит так: [(Any, x)] -> [(y, Any)] -> [(x, y)] на входе [(«a», 2) (3,4)] –

+1

Это будет очень хрупким, я не уверен, зачем вам экзистенциальный Любой тип, если вы никогда не сможете использовать его для чего-либо конкретного. 'Data.Dynamic'' является предпочтительным способом обработки типов, которые неизвестны до выполнения. –

ответ

6

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

Термин «Любой-производитель» Функция

f :: ... -> Any 

может быть использован для получения значения, которое любого типа: он возвращает строку, которая также является целым числом и пара, и слон в то же время , Конкретно, он возвращает дно (или он не возвращается вообще, если вы предпочитаете).

Термин «Любой-потребитель» Функция

f :: Any -> ... 

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

Вы пытаетесь передать 2, который не любого типа - это только любой цифровой типа. Отсюда ошибка типа.

Если вы хотите, чтобы написать функцию, которая принимает что-либо, вы должны написать

type Any = exists a. a -- INVALID Haskell 
f :: Any -> ... 

, но увы, Haskell не позволяет такого рода экзистенциальных типов. Если вы хотите, что типа вы должны боксировать его:

data Any = forall a . Any a 
f :: Any -> ... 

caller = f (Any 'd') 

В качестве альтернативы, вы можете поднять exists до верхнего уровня. Так как он находится в отрицательной позиции, он становится forall

f :: (exists a. a) -> ... 
-- becomes 
f :: forall a. (a -> ...) 
+0

Ух, я забыл про продюсера. Это полностью разрушило бы безопасность типа. Грустный. –

5

По-видимому, из комментариев возникает реальный вопрос: как я набираю список, написанный с литеральным синтаксисом ["a", False]?

Ответ (к счастью!) - это «вы не можете».

Вы можете сделать экзистенциальный тип и обернуть каждый элемент экзистенциальным. Если вы хотите сделать это, вы можете сделать это следующим образом:

{-# LANGUAGE GADTs #-} 
data Box where 
    Box :: a -> Box 

Затем список [Box "a", Box False] будет хорошо набирается на тип [Box]. Тем не менее, если вы готовы применить функцию к каждому элементу, то вы можете спокойно пропустить все махинации типа и сделать что-то вроде этого, вместо:

toss :: a ->() 
toss _ =() 

[toss "a", toss False] Тогда имеет очень понятный тип [()].

3

Он не может работать, потому что ваш Any фактически All. Он может быть построен только из выражения, имеющего все типы (что-то вроде undefined).

Вам нужно будет использовать {-# LANGUAGE ExistentialQuantification #-} to build a real Any`:

data Any = forall a . Any a 

Это должно быть типом данных, так что вам придется создавать ценности с помощью Any конструктор, но теперь вы можете сделать что-то вроде этого:

f :: [(x, Any)] -> [(Any, y)] -> [(x,y)] 
f ((x, _) : xs) ((_, y) : ys) = (x,y) : f xs ys 
f _ _ = [] 

> f [("hi", Any 'a'),("you", Any 3)] [(Any "a", 2),(Any Nothing, 4)] 
[("hi",2),("you",4)] 
+0

Тип осложняет все, что я пытался сделать с этим. Но, спасибо за ваш ответ. Это довольно круто. –

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