1

我试图想出一个可以像这样应用的函数的定义:

setProperty Left 45 Px
setProperty Position Absolute
setProperty Visible True

我试过GADTs

data StyleUnit = Px | Pct | Em
data PositionP = Absolute | Relative | Static

data Property a where
  Position :: Property PositionP
  Left :: Property (Integer -> StyleUnit)
  Visible :: Bool

使用以下签名:

setProperty :: Property a -> a -> IO ()

但不幸的是,这似乎不起作用。这是完全可以实现的,还是我最好只拥有专门的功能版本,比如setPropertyPositionsetPropertyLeft等等?

4

3 回答 3

1

我首先尝试从问题中解释代码中发生了什么,然后建议将镜头作为替代解决方案。

一个易于修复的编译错误

首先,您的数据定义会产生错误,因为 的类型Visible不以Property. 你想要这个:

data Property a where
  Position :: Property PositionP
  Left :: Property (Integer -> StyleUnit)
  Visible :: Property Bool

一个问题Left

现在您可以编写以下内容:

setProperty :: Property a -> a -> IO ()
setProperty = undefined

但是 的类型存在问题setProperty Left,因为您可以签入ghci(您可能希望使其import Prelude hiding (Left)正常工作)。

:t setProperty Left
setProperty Left :: (Integer -> StyleUnit) -> IO ()

我不认为那是你想要的类型。你可能想要Integer -> StyleUnit -> IO ()

进入IO ()数据类型

实现这一目标的最简单方法是将 移动IO ()Property数据类型中:

data Property a where
  Position :: Property (PositionP -> IO ())
  Left :: Property (Integer -> StyleUnit -> IO ())
  Visible :: Property (Bool -> IO ())

setProperty :: Property a -> a
setProperty = undefined

这可能适用于setProperty,但不清楚如何编写getProperty,我猜你也想拥有。

使用对

也许最好只使用一对值和单位:

data Property a where
  Position :: Property PositionP
  Left :: Property (Integer, StyleUnit)
  Visible :: Property Bool

setProperty :: Property a -> a -> IO ()
setProperty = undefined

这给了你:

:t setProperty Left
setProperty Left :: (Integer, StyleUnit) -> IO ()

您应该能够实施。

这真的是要走的路吗?

在不知道你问题的背景的情况下,我不能说这是否真的是要走的路。对于一个简单的目标来说,这似乎是相当复杂的技术。setPositionsetLeft有什么问题setVisible?如果您只想将 setter 和 getter 组合成一个抽象,您可能需要研究镜头。

于 2013-08-19T08:44:43.213 回答
1

您可以使用 TypeFamilies 来解决此问题。仅当它们具有相似的语义时才建议这样做,否则它们的使用可能会使用户感到困惑。我不确定你的类型,所以我在下面的示例实现中对它们进行了一些修改。

{-# LANGUAGE TypeFamilies     #-}
{-# LANGUAGE FlexibleContexts #-}

data StyleUnit = Px | Pct | Em
data PositionP = Absolute | Relative | Static
data Visible = Visible

class Property a where
  type PropertyVal a :: *
  setProperty :: (PropertyVal a) -> a -> IO ()

instance Property StyleUnit where
  type PropertyVal StyleUnit = Either Int Int
  setProperty a _ = print a

instance Property PositionP where
  type PropertyVal PositionP = ()
  setProperty a _ = print a

instance Property Visible where
  type PropertyVal Visible = Bool
  setProperty a _ = print a
于 2013-08-19T07:06:16.283 回答
0

Not sure what exactly you mean by setProperty. If you mean create property, you can do something like this:

data StyleUnit = Px | Pct | Em
data PositionP = Absolute | Relative | Static

data Property a where
  Position :: PositionP -> Property PositionP
  Left :: (Integer,StyleUnit) -> Property (Integer, StyleUnit)
  Visible :: Bool -> Property Bool

setProperty :: (a -> Property a) -> a -> Property a
setProperty = ($)

Examples:

setProperty Left (45,Px)
于 2013-08-19T08:01:46.807 回答