我正在尝试提出一个可以像这样应用的函数定义:
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 ()
但不幸的是,这似乎不起作用。这是完全可以实现的,还是我最好只拥有专门的功能版本,比如setPropertyPosition
,setPropertyLeft
等等?
答案 0 :(得分: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
答案 1 :(得分: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 ()
您应该能够实施哪些。
在不知道问题的背景的情况下,我不能说这是否真的是要走的路。对于一个简单的目标来说,这似乎是相当复杂setPosition
,setLeft
和setVisible
出了什么问题?如果你只想将一个setter和一个getter组合成一个抽象,你可能想看一下镜头。
答案 2 :(得分:0)
不确定setProperty
到底是什么意思。如果您的意思是创建属性,您可以执行以下操作:
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 = ($)
示例:
setProperty Left (45,Px)