Подтвердить что ты не робот

Есть ли тип "Any" в haskell?

Скажем, я хочу определить атрибут записи следующим образом:

data Attribute = Attribute {name :: String, value :: Any}

Это, конечно, неверный код haskell. Но есть ли тип "Любой", который в принципе скажет, что любой тип будет делать? Или использовать переменную типа единственный способ?

data Attribute a = Attribute {name :: String, value :: a}

4b9b3361

Ответ 1

Вообще говоря, типы Any не очень полезны. Рассмотрите: если вы делаете полиморфный список, который может содержать что-либо, что вы можете делать с типами в списке? Ответ, конечно, ничто - у вас нет гарантии, что для этих элементов существует какая-либо операция.

Что обычно будет делать:

  • Используйте GADTs, чтобы создать список, который может содержать элементы определенного типа, например:

    data FooWrap where
        FooWrap :: Foo a => a -> FooWrap
    type FooList = [FooWrap]
    

    При таком подходе вы не знаете конкретного типа элементов, но знаете, что их можно манипулировать с помощью элементов класса Foo.

  • Создайте тип для переключения между конкретными конкретными типами, содержащимися в списке:

    data FooElem = ElemFoo Foo | ElemBar Bar
    type FooList = [FooElem]
    

    Это можно объединить с подходом 1, чтобы создать список, который может содержать элементы, которые имеют один из фиксированных наборов типов.

  • В некоторых случаях может быть полезно создать список функций манипуляции:

    type FooList = [Int -> IO ()]
    

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

  • Используйте Data.Dynamic (не рекомендуется!) как обманщик. Однако это не гарантирует, что какой-либо конкретный элемент можно вообще манипулировать, и поэтому предпочтительные подходы должны быть предпочтительными.

Ответ 2

Добавление в ответ bdonlan: вместо GADT вы также можете использовать экзистенциальные типы:

{-# LANGUAGE ExistentialQuantification #-}

class Foo a where
  foo :: a -> a

data AnyFoo = forall a. Foo a => AnyFoo a

instance Foo AnyFoo where
  foo (AnyFoo a) = AnyFoo $ foo a

mapFoo :: [AnyFoo] -> [AnyFoo]
mapFoo = map foo

Это в основном эквивалентно решению bdonlan GADT, но не налагает на вас выбор структуры данных. Вместо списка вы можете использовать Map, например:

import qualified Data.Map as M

mFoo :: M.Map String AnyFoo
mFoo = M.fromList [("a", AnyFoo SomeFoo), ("b", AnyFoo SomeBar)]

Бит data AnyFoo = forall a. Foo a => AnyFoo a также может быть записан в нотации GADT как:

data AnyFoo where
  AnyFoo :: Foo a => a -> AnyFoo

Ответ 3

Существует тип Dynamic из Data.Dynamic, который может содержать что угодно (ну, что-нибудь Typeable). Но это редко бывает правильным способом. В чем проблема, которую вы пытаетесь решить?

Ответ 4

Это звучит как довольно простой вопрос, поэтому я собираюсь дать более общий ответ, чем кто-либо другой. Здесь почти всегда правильное решение:

data Attribute a = Attribute { name :: String, value :: a }

Затем, если вам нужен атрибут, который обертывает Int, этот атрибут будет иметь тип Attribute Int, или атрибут, который обертывает Bool, будет иметь тип Attribute Bool и т.д. Вы можете создать эти атрибуты с помощью значения любого типа; например, мы можем написать

testAttr = Attribute { name = "this is only a test", value = Node 3 [] }

чтобы создать значение типа Attribute (Tree Int).

Ответ 5

Если ваши данные должны быть в конечном итоге конкретным типом, вы можете использовать Convertible с GADT. Потому что, как потребитель, вас интересует только тип данных, который вам нужно потреблять.

{-# LANGUAGE GADTs #-}
import Data.Convertible 

data Conv b where 
   Conv ::  a -> (a -> b) -> Conv b
   Chain :: Conv b -> (b -> c) -> Conv c

unconv :: (Conv b) -> b 
unconv (Conv a f) = f a
unconv (Chain c f) = f $ unconv c

conv :: Convertible a b => a -> Conv b 
conv a = (Conv a convert)

totype :: Convertible b c => Conv b -> Conv c
totype a = Chain a convert

Не так сложно получить для этого функторы, экземпляры comonad и monad. Я могу опубликовать их, если вы заинтересованы.