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)
только ""
, если хотите; в зависимости от того, что вам легче читать.