2011-01-05 5 views
4

Я не понимаю, почему я не могу построить список, который выглядит как [1,"1",1.1] в haskell. Я не думаю, что это статическая типизация, которая мешает мне, потому что я думал, что у head теперь будет плохо определенный тип, но потом я подумал об этом, и нет причин, чтобы система времени выполнения не создавала экземпляр другой версии head всякий раз, когда в него вводится список, поэтому head [1,"1",1.1] будет набираться как List->Int, а head (tail [1,"1",1.1]) будет набираться как List->String. Поскольку время выполнения уже делает много бухгалтерского учета, почему он не предоставляет более эффектные полиморфные (или это общие) версии различных функций прелюдии? Что мне здесь не хватает?Почему у haskell нет гетерогенных списков

+0

Какой тип является Nth элемент '[1, "1", 1,1]'? – Gabe

+0

@Gabe: дайте мне конкретный номер, и я однозначно скажу вам, что это такое. Время компиляции или время выполнения. – davidk01

+3

@ davidk01: скажите мне тип 4-го элемента списка _variable _... другими словами список, являющийся аргументом функции?Если уж на то пошло, скажите мне, будет ли это даже 4-й элемент, во время компиляции! Если список или индекс являются переменной, вы не можете знать тип во время компиляции. –

ответ

16

Это действительно типизация, которая предотвращает это. Рассмотрим определение списка (обратите внимание на параметр типа a, который отсутствует из ваших типов):

data List a = Nil | Cons a (List a) 

В Cons a (List a) вы можете увидеть, что тип вещи во главе списка должен быть тот же тип как элементы, которые следуют за ним. Чтобы ответить на ваш вопрос, вы не пропустите много: как вы говорите, время выполнения может это сделать, но в Haskell вы хотите принять эти решения для ввода во время компиляции, а не во время выполнения.

Если вам нужны гетерогенные списки, вы можете увидеть некоторое колдовство Олега Киселева в его работе на HList (= Гетерогенный список). Это может быть не совсем то, что вы хотите, но оно находится в одном и том же направлении.

+1

+1 для HList !!! – Landei

+5

И для ясности, «гетерогенные списки» HList действительно ничем не отличаются от правильных вложенных 2-х кортежей. Интересная часть состоит не в самих списках, а в сумасшедшем мета-программировании глубокого волшебства уровня, который использует Олег, для создания общих функций, которые работают на произвольных «списках». –

+2

@ davidk01: выше, что вам действительно нужно знать. На этом этапе обучения вам не нужно знать о HList или других типах хакеров. Сначала изучите основы. –

3

Потому что в Haskell все типы известны во время компиляции. Нет такой вещи, как дожидаться времени выполнения, чтобы узнать, какой тип будет. И потому, что этого достаточно, чтобы делать все, что вы могли бы захотеть сделать в динамически типизированной системе, будучи легче рассуждать о загрузке.

+0

Вы не ответили на мой вопрос. В примерах, которые я дал, все типы все еще известны во время выполнения. Если я дам вам список '[1," 1.1 ", 1.1]' и попрошу вас вычислить 'head [1," 1.1 ", 1.1]', тогда результат однозначно будет означать 'Int', находитесь ли вы во время компиляции или время выполнения. – davidk01

+1

@ davidk01: он будет известен во время выполнения, да, но не во время компиляции. Легко видеть, что тип второго элемента '[1," 1.1 ", 1.1]' есть, потому что вы смотрите на литерал списка, но что, если вы пытаетесь определить n-й элемент произвольного список, который является аргументом функции? –

+0

@Gabe: система типов уже много вычисляет при определении типов. Нет причин, по которым он не может пройти лишнюю милю и введите все примеры, которые я дал во время компиляции. – davidk01

3

Как вы знаете, на самом деле существует пакет для гетерогенных списков с использованием нетривиальных методов, и вы действительно должны убедиться, что вы хорошо понимаете систему типов, прежде чем погрузиться в это. У вас нет этого по умолчанию из-за системы типов. Список в Haskell - это не просто список. Это список, 'a', являющийся Int, String, независимо от того, что вы хотите. НО, один список может содержать только один тип значений.

Обратите внимание, что вы можете определить «гетерогенные списки» элементов, удовлетворяющих некоторым ограничениям, используя экзистенциальную количественную оценку, но я думаю, что вас еще нет, и на самом деле нужно сосредоточиться на понимании других ответов здесь, прежде чем идти дальше.

+0

+1 для важного момента, что списки Haskell предназначены для * списка *. –

3

Существует гетерогенный тип списка HList (доступен в Hackage), но обратите внимание, что, вероятно, существует тип содержимого вашего списка. Рассмотрим что-то вроде этого:

history = [-12, "STATEMENT END", (-244, time January 4 2010), ...] 

Ваши данные имеют тип борющегося появляться, например .:

data HistoryEntry = Withdrawal Int | StatementClosing | ScheduledPayment Int CalendarTime 

history = [Withdrawal 12, StatementClosing, ScheduledPayment 244 (time January 4 2010)] 

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

3

Посмотрите на Heterogenous collections

{-# OPTIONS -fglasgow-exts #-} 
-- 
-- An existential type encapsulating types that can be Shown 
-- The interface to the type is held in the show method dictionary 
-- 
-- Create your own typeclass for packing up other interfaces 
-- 
data Showable = forall a . Show a => MkShowable a 

-- 
-- And a nice existential builder 
-- 
pack :: Show a => a -> Showable 
pack = MkShowable 

-- 
-- A heteoregenous list of Showable values 
-- 
hlist :: [Showable] 
hlist = [ pack 3 
     , pack 'x' 
     , pack pi 
     , pack "string" 
     , pack (Just()) ] 

-- 
-- The only thing we can do to Showable values is show them 
-- 
main :: IO() 
main = print $ map f hlist 
    where 
     f (MkShowable a) = show a 

{- 

*Main> main 
["3","'x'","3.141592653589793","\"string\"","Just()"] 

-} 
+0

Это не HList, это экзистенциальные типы. – AndrewC