如何编写一个可以在“obj”以及“Maybe obj”上调用“getField @k”的 Haskell 函数

问题描述 投票:0回答:1

我正在尝试编写 HTML 表单助手,我希望调用站点支持以下两种用例:

{-# LANGUAGE AllowAmbiguousTypes, DataKinds, OverloadedStrings #-}

import Data.Proxy
import Data.Text as Text
import GHC.Generics
import GHC.Records
import GHC.TypeLits

data FormCtx obj = FormCtx { ctxFieldNamePrefix :: !Text, ctxObject :: !obj } 
data MyRecord = MyRecord { field1 :: !Text, field2 :: !Text } deriving (Generic)

-- USE-CASE #1
let ctx = FormCtx "MyRecord" obj
in (fieldNameFor @"field1" ctx, fieldValueFor @"field1" ctx)

-- USE-CASE #2 -- with a (Maybe obj)
let ctx = FormCtx "MyRecord" (Just obj)
in (fieldNameFor @"field1" ctx, fieldValueFor @"field1" ctx)

-- Implementation for fieldNameFor which works only 
-- with `obj`, and not `Maybe obj`
fieldNameFor :: forall k obj a . (KnownSymbol k, HasField k obj a) => FormCtx obj -> Text
fieldNameFor FormCtx {ctxFieldNamePrefix} = ctxFieldNamePrefix <> "[" <> (Text.pack $ symbolVal (Proxy @k)) <> "]"

-- Implementation for fieldValueFor which works only 
-- with `obj`, and not `Maybe obj`
fieldValueFor :: forall k obj a . (KnownSymbol k, HasField k obj a) => FormCtx obj -> a
fieldValueFor FormCtx {ctxObject} = getField @k ctxObject

我尝试定义一个名为

FieldNameFor
的类型类,以便能够为
obj
Maybe obj
定义重叠实例,但我无法使其与
KnownSymbol k, HasField k obj a
所需的类型类约束一起使用
getField
上班。

haskell record typeclass
1个回答
0
投票

这不是很漂亮,但是很有效。只需用它替换现有的

fieldValueFor
即可:

{-# LANGUAGE TypeFamilies #-}

type family CopyMaybe a b where
    CopyMaybe (Maybe a) b = Maybe b
    CopyMaybe a b = b

class FieldValueFor k obj a where
    fieldValueFor :: FormCtx obj -> CopyMaybe obj a

instance {-# OVERLAPPABLE #-} (KnownSymbol k, HasField k obj a, CopyMaybe obj a ~ a) => FieldValueFor k obj a where
    fieldValueFor FormCtx {ctxObject} = getField @k ctxObject

instance (KnownSymbol k, HasField k obj a) => FieldValueFor k (Maybe obj) a where
    fieldValueFor FormCtx {ctxObject} = getField @k <$> ctxObject

对于

fieldNameFor
来说更简单:只需删除
HasField k obj a
约束(它一直都是多余的),然后您现有的实现就可以工作了。

© www.soinside.com 2019 - 2024. All rights reserved.