Начиная с вашего примера
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds, KindSignatures #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wall #-}
import Data.Type.Equality
data Car
data Food
data CarRental = CarRental {passengers :: Int, mileage :: Int}
deriving (Eq, Ord)
data ErrandList = ErrandList {avoidJunkFood :: Bool}
deriving (Eq, Ord)
data GetStuff a where
RentACar :: CarRental -> GetStuff Car
BuyFood :: ErrandList -> GetStuff Food
data Some t = forall a. Some (t a)
Вам нужно будет написать экземпляр http://hackage.haskell.org/package/dependent-sum-0.4/docs/Data- GADT-Compare.html # t: GEq
class GEq f where
geq :: f a -> f b -> Maybe (a :~: b)
Тогда вы сможете определить экземпляр Eq (Some f)
instance GEq f => Eq (Some f) where
Some fa == Some fb = case geq fa fb of
Just Refl -> True
Nothing -> False
Запись экземпляра вручную повторяющийся, но не ужасный. Обратите внимание, что я написал в пути без «поймать все» в последнем случае.
instance GEq GetStuff where
geq (RentACar x) z = case z of
RentACar x' -> if x == x' then Just Refl else Nothing
_ -> Nothing
geq (BuyFood x) z = case z of
BuyFood x' -> if x == x' then Just Refl else Nothing
_ -> Nothing
Существует класс GCompare
для Ord
ГАДЦ.
Таким образом, проблема сводится к «как получить GEq
или GCompare
автоматически». Я думаю, что для специальных GADT, таких как ваш GetStuff
, вы можете написать quick-n-dirty TH, чтобы сгенерировать код.
Generic
-подобная альтернатива, о которой я могу подумать, потребует от вас написания функций преобразования из и в GetStuff
, что может быть выигрышным, если вам нужно написать более общие функции. Давайте также исследуем это. Сначала мы определим общее представление GADT, которые нас интересуют:
data Sum (cs :: [(*, *)]) a where
Z :: a :~: c -> b -> Sum ( '(c, b) ': cs) a
S :: Sum cs a -> Sum (c ': cs) a
Мы можем конвертировать между GetStuff
и Sum
. То, что нам нужно написать для каждого GADT, это O (n) , где n
- количество конструкторов.
type GetStuffCode =
'[ '(Car, CarRental)
, '(Food, ErrandList)
]
toSum :: GetStuff a -> Sum GetStuffCode a
toSum (RentACar x) = Z Refl x
toSum (BuyFood x) = S (Z Refl x)
fromSum :: Sum GetStuffCode a -> GetStuff a
fromSum (Z Refl x) = RentACar x
fromSum (S (Z Refl x)) = BuyFood x
fromSum (S (S x)) = case x of {} -- silly GHC requires this :)
Теперь, когда у нас есть общее представление, Sum
, мы можем написать общие функции. Равенство, GGEq
для Родовое равенство Гадта Класс выглядит как GEq
, но мы используем Sum
в качестве аргументов.
class GGEq code where
ggeq :: Sum code a -> Sum code b -> Maybe (a :~: b)
Нам понадобятся два экземпляра для кодов nil и cons :
instance GGEq '[] where
ggeq x _ = case x of {}
instance (Eq b, '(x, b) ~ c, GGEq cs) => GGEq (c ': cs) where
ggeq (Z Refl x) (Z Refl y) = if x == y then Just Refl else Nothing
ggeq (S x) (S y) = ggeq x y
ggeq (Z _ _) (S _) = Nothing
ggeq (S _) (Z _ _) = Nothing
Используя этот механизм, написание geq
для GetStuff
тривиально: [ 1140]
geq1 :: GetStuff a -> GetStuff b -> Maybe (a :~: b)
geq1 x y = ggeq (toSum x) (toSum y)
echo Hello, > file.txt
echo. >>file.txt
echo world >>file.txt
, и вы всегда можете запустить:
wordpad file.txt
в любой версии Windows.
В Windows 2000 и выше вы можете сделать:
( echo Hello, & echo. & echo world ) > file.txt
Еще один способ показать сообщение для небольшого количества текста - создать файл file.vbs, содержащий:
Msgbox "Hello," & vbCrLf & vbCrLf & "world", 0, "Message"
вызовите его с помощью
cscript /nologo file.vbs
или используйте wscript
, если вам не нужно ждать, пока они не нажмут OK.
Проблема с сообщением Вы пишете, что вертикальная черта ( |
) является оператором "pipe" . Вам нужно будет избежать его, используя ^ |
вместо |
.
PS оно пишется Pwned .
Вы можете легко добавить в конец файла, дважды используя символ перенаправления ( >>
).
Это скопирует source.txt
- destination.txt
, перезаписывает место назначения в процессе:
type source.txt > destination.txt
Это скопирует source.txt
в destination.txt
, добавляя к месту назначения в процесс:
type source.txt >> destination.txt
Может быть, это то, что вы хотите?
echo foo > test.txt
echo. >> test.txt
echo bar >> test.txt
приводит к следующему в test.txt:
foo
bar