如何构造grpc-proto-lens生成对象?解决类型构造器非法使用问题
如何构造grpc-proto-lens生成的gRPC数据对象?
我的proto定义如下:
message PortfolioRequest { string account_id = 1; }
使用http2-grpc-haskell(基于grpc-proto-lens)生成代码后,我尝试用let pr = PortfolioRequest (T.pack "0")创建对象,却报错Illegal term-level use of the type constructor。生成的Haskell代码如下:
{- | Fields : * 'Proto.Invest.Operations_Fields.accountId' @:: Lens' PortfolioRequest Data.Text.Text@ -} data PortfolioRequest = PortfolioRequest'_constructor {_PortfolioRequest'accountId :: !Data.Text.Text, _PortfolioRequest'_unknownFields :: !Data.ProtoLens.FieldSet} deriving stock (Prelude.Eq, Prelude.Ord) instance Prelude.Show PortfolioRequest where showsPrec _ __x __s = Prelude.showChar '{' (Prelude.showString (Data.ProtoLens.showMessageShort __x) (Prelude.showChar '}' __s)) instance Data.ProtoLens.Field.HasField PortfolioRequest "accountId" Data.Text.Text where fieldOf _ = (Prelude..) (Lens.Family2.Unchecked.lens _PortfolioRequest'accountId (\ x__ y__ -> x__ {_PortfolioRequest'accountId = y__})) Prelude.id instance Data.ProtoLens.Message PortfolioRequest where messageName _ = Data.Text.pack "tinkoff.public.invest.api.contract.v1.PortfolioRequest" packedMessageDescriptor _ = "\n\DLEPortfolioRequest\DC2\GS\n\naccount_id\CAN\SOH \SOH(\tR\taccountId" packedFileDescriptor _ = packedFileDescriptor fieldsByTag = let accountId__field_descriptor = Data.ProtoLens.FieldDescriptor "account_id" (Data.ProtoLens.ScalarField Data.ProtoLens.StringField :: Data.ProtoLens.FieldTypeDescriptor Data.Text.Text) (Data.ProtoLens.PlainField Data.ProtoLens.Optional (Data.ProtoLens.Field.field @"accountId")) :: Data.ProtoLens.FieldDescriptor PortfolioRequest in Data.Map.fromList [(Data.ProtoLens.Tag 1, accountId__field_descriptor)] unknownFields = Lens.Family2.Unchecked.lens _PortfolioRequest'_unknownFields (\ x__ y__ -> x__ {_PortfolioRequest'_unknownFields = y__}) defMessage = PortfolioRequest'_constructor {_PortfolioRequest'accountId = Data.ProtoLens.fieldDefault, _PortfolioRequest'_unknownFields = []}
解决方法
从生成的代码可以看出,PortfolioRequest是类型构造器,不能直接在值层面调用。实际的数值构造器是PortfolioRequest'_constructor,不过更推荐使用proto-lens的标准方式构造消息对象:
方法1:默认消息+Lens修改(推荐)
这是proto-lens官方推荐的方式,先获取默认消息实例,再通过生成的Lens设置目标字段:
import Data.ProtoLens (defMessage) import Proto.Invest.Operations_Fields (accountId) -- 导入生成的字段Lens import qualified Data.Text as T let pr = defMessage & accountId .~ T.pack "0"
方法2:直接调用生成的构造器
如果需要直接使用构造器,注意构造器名称是PortfolioRequest'_constructor,且必须同时指定_unknownFields字段(传空FieldSet即可):
import qualified Data.Text as T import Data.ProtoLens (FieldSet) let pr = PortfolioRequest'_constructor (T.pack "0") []
错误原因说明
你写的PortfolioRequest (T.pack "0")是把类型构造器当作值构造器使用了。Haskell中类型和值属于不同的命名空间,类型构造器只能在类型层面使用,不能直接用来创建值,因此触发了Illegal term-level use of the type constructor错误。
内容的提问来源于stack exchange,提问作者Miezhiko
相关产品推荐
相关产品推荐

