包含对数据和字符串的操作的类的字符串实例

时间:2014-06-18 23:45:29

标签: haskell

我想在一个涉及在图像上排列文本和对象的应用程序中使用Haskell自定义运算符。例如,我将有一个垂直构图的运算符:将一个元素放在另一个元素上面。我们称之为|||。

让我们声明一个数据类型Element来表示可视对象。一种可视元素可能是字符串中指定的某些文本。在视觉上,这会创建一些默认字体和大小的单词。另一种视觉元素可能是JPEG文件。所以我们有

type Filename = String

data Element = EString String
             | EJpeg Filename
             | EVerticalComposition Element Element

我可以声明|||运算符如下:

(|||) :: Element -> Element -> Element

但是,为简洁起见,我想写一些类似的东西

composedElem = "some words" ||| "some words that appear below" 
               ||| "and more words"

请注意,我不想在每个字符串前面添加EString。

所以我觉得我需要|||成为包含String实例和Element实例的类型类的一部分。我可能会有这样的事情:

class ImageClass a where
    (|||) :: a -> a -> a

instance ImageClass String where
    (|||) x y = EVerticalComposition x y

但假设(|||)是左关联的,我在上面几个术语的表达中使用它,我还需要(|||)来操作Elmeents,比如

(|||) :: Element -> String -> Element

这甚至可能吗?或者,如果是这样,值得吗?我也可以这样编写我的小程序:

composedElem = EString "some Words" ||| "some words that appear below"
               ||| "and more words" 

但是如果用(|||)来放置其他类型的元素呢?我不想把构造函数放在所有东西面前,只是为了简洁起见,除非这太复杂而无法实现。

1 个答案:

答案 0 :(得分:3)

最好的方法是使用类将自定义类型转换为Element,然后让运算符|||获取该类的泛型参数。

例如:

{-# LANGUAGE FlexibleInstances #-}
module Main where
type Filename = String

data Element = EString String
             | EJpeg Filename
             | EVerticalComposition Element Element
  deriving (Show)



class AsElement a where
  toElement :: a -> Element

instance AsElement Element where
  toElement = id
instance AsElement String where
  toElement = EString

(|||) :: (AsElement a, AsElement b) => a -> b -> Element
a ||| b = EVerticalComposition (toElement a) (toElement b)

infixl 4 |||




testElement1 :: Element
testElement1 = "this" ||| "that"

testElement2 :: Element
testElement2 = "this" ||| EJpeg "lol" ||| "another"

结果:

λ> testElement1
EVerticalComposition (EString "this") (EString "that")
λ> testElement2
EVerticalComposition (EVerticalComposition (EString "this") (EJpeg "lol")) (EString "another")

只需添加AsElement的更多实例即可添加更多类型。