Haskell: как набирать текст

С#:

static int F(object x)
{
 return x is string ? 1 : 2;
}

Haskell? Мне кажется, что хитовый бит мне кажется, что у Haskell нет объекта типа корня.

Отредактировано: меня не интересует преобразование в строку. Я хочу знать, как придать тип (например, чтобы увидеть, является ли объект Заказчиком или Заказ.

Ответ 1

В Haskell все типы, которые допускают преобразование в строку, создают экземпляр Show, который обеспечивает

show :: Show a => a -> String

Итак, весь ваш код - это ничего, кроме

f x = show x

или

f = show

с тем же общим типом f :: Show a => a -> String (Forall types a, которые можно передать в строку, взять значение этого типа и вернуть строку).

Обратите внимание, что вам не нужно выполнять явную проверку типа времени выполнения, как в С#; общий шаблон разрешается во время компиляции. Вам не нужен полиморфный корневой тип. Листинг, похожий на С#, на самом деле будет несколько сложным и против языковой концепции. Вместо того, чтобы допускать произвольные отбрасывания между типами, он определял типы классов для определенных значимых преобразований.

Обратите внимание, что совместимость проверяется во время компиляции:

-- Working
f 1
f "Hallo"
f (1, 2)
f [1, 2, 3]

-- Not working
f (\x -> x + 1) 

В ответ на ваш отредактированный вопрос:

Как я уже говорил, произвольные преобразования в Haskell запрещены (без очень очень небезопасного кода). А поскольку Haskell не является объектно-ориентированным, отношения наследования не требуются. Там просто не бессмысленные значения object, которые нуждались в проверке/литье времени выполнения. Для выражения альтернатив вам нужно будет определить тип объединения, тип класса или использовать тип Either.

В каком случае вы сталкиваетесь с объектом, который является Customer или Order? Значение этого типа просто бессмысленно. Просьба уточнить еще раз.

Что касается вашего примера регистрации: Вам понадобится класс:

class Loggable a where
    writeToLog :: a -> IO ()

Ответ 2

Дарио справа, как правило, в Haskell вы хотите создать класс типа для отправки по типу. Это, как говорится, есть безопасный способ типа бросить в Haskell. Это часть Отмените свою стандартную библиотеку программирования, которая позволяет вам писать "интересные" части манипуляций сложными вложенными типами данных, в то время как SYB заполняет пробелы. Мозг плавно оглушительный. Здесь презентация на нем в ppt или html.

Вот что выглядит приведение:

cast :: (Typeable a, Typeable b) => a -> Maybe b
ghci> (cast 'a') :: Maybe Char
Just 'a'
ghci> (cast 'a') :: Maybe Bool
Nothing
ghci> (cast True) :: Maybe Bool
Just True

Ответ 3

Кастинг и is/instanceof имеют смысл на языках, которые показывают subtyping. На ваш вопрос можно ответить несколькими способами:

  • Haskell не имеет подтипирования, поэтому is/instanceof не имеет смысла в Haskell; есть только явные преобразования. Нет типа object, из которого расширяются все типы.
  • Классы типа Haskell предлагают ad-hoc-полиморфизм и помогают перегружать одно имя для многих преобразований. Например (как указывали другие) show - это перегруженное имя для преобразования любого типа в String. Классы типов также могут использоваться для того, чтобы сделать определенные преобразования (кажущиеся) неявными.
  • Используя классы типов, авторы общей библиотеки Scrap Your Boilerplate создали безопасную функцию трансляции (также указали другие).

Ответ 4

Если вы хотите иметь объекты, которые могут быть Клиентами или Ордерами, то вы вводите новый тип данных "Заказчик", чтобы каждый объект имел тег типа, который указывает, что это такое.

Я не знаю синтаксис Haskell, но в F # это будет

type CustOrOrd =
    | Cust of Customer
    | Ord of Order

let F (x:CustOrOrd) : int =
    match x with
    | Cust c -> 1
    | Ord o -> 2

let thing1 = Cust someCustomer
let thing2 = Ord someOrder
// can call F on thing1 or thing2

В более общем плане, в Haskell, если вы хотите сделать что-то вроде фиксированной иерархии типов OO (для фиксированного набора сильно связанных типов, чтобы иметь возможность рассматривать их как один и тот же тип в некоторых случаях), вы можете использовать объединение типа, как указано выше. С другой стороны, для общих операций во множестве несвязанных типов (например, ToString/Show) вы можете использовать класс типа Haskell.

Ответ 5

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

Введение в Чистые функции Haskell

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

Ответ 6

Самый простой способ - использовать Data.Typeable, как отмечает Дарио, который охватывает все стандартные типы, хотя вам нужно пройти "Deriving Typeable" или иным образом реализовать typeOf для определения вашего собственного типа. Это не стандартный Haskell 98, но он находится в ghc с 6.2.2.

Ваш код может быть реализован:

 stringtyperep :: TypeRep
 stringtyperep = typeOf "somestring"

 F :: (Typeable 'a) =>'a -> Integer
 F x | (typeOf x == stringtyperep) = 1
 F x = 2

В общем, отражение типа OO лучше делать с помощью общего программирования, но это не будет хорошим примером для этого.

Кроме того, все типы в typeclass Typeable могут быть "отлиты" в Data.Dynamic.

Ответ 7

В С# это, скорее всего, более эффективно, чем делать:

return x == null ? null : x.ToString();

В Haskell есть класс типа "show", все, что реализует класс типа, может иметь шоу, вызываемое на нем, и поэтому не требуется кастинг.

Ответ 8

Определите Object самостоятельно

Если ваш прецедент довольно прост, возможно, лучше всего просто определить тип объекта, таким образом:

data Type = String | Integer | List | Bool
    deriving (Eq, Show)

class Object a where
    typeOf :: a -> Type

instance Object String  where typeOf _ = String
instance Object Integer where typeOf _ = Integer
instance Object [a]     where typeOf _ = List
instance Object Bool    where typeOf _ = Bool

f :: (Object a, Num b) => a -> b
f x = if typeOf x == String then 1 else 2

Очевидно, вам нужно написать объявление instance для каждого типа, который вы можете использовать как объект в своей функции, который использует typeOf. Это может оказаться сложным, если вы пытаетесь определить instance для кортежей, потому что в Haskell два кортежа имеют разные типы, если они не имеют одинакового количества элементов, поэтому вам может потребоваться написать бесконечное число объявлений instance, скорее так:

data Type = String | Integer | List | Bool | Tuple
    deriving (Eq, Show)

instance Object ()              where typeOf _ = Tuple
instance Object (a)             where typeOf _ = Tuple
instance Object (a,b)           where typeOf _ = Tuple
instance Object (a,b,c)         where typeOf _ = Tuple
instance Object (a,b,c,d)       where typeOf _ = Tuple
instance Object (a,b,c,d,e)     where typeOf _ = Tuple
instance Object (a,b,c,d,e,f)   where typeOf _ = Tuple
instance Object (a,b,c,d,e,f,g) where typeOf _ = Tuple

Используйте Data.Typeable

Если ваше использование усложняется, вы можете попробовать Data.Typeable:

import Data.Typeable

f :: (Typeable a, Num b) => a -> b
f x = if typeOf x == typeOf (undefined::String) then 1 else 2

Вы можете заменить (undefined::String) только "", если хотите; в зависимости от того, что вам легче читать.