当前位置:  开发笔记 > 编程语言 > 正文

如何使用最少的样板处理"typedef"式数据类型?

如何解决《如何使用最少的样板处理"typedef"式数据类型?》经验,为你挑选了1个好方法。

我定义了一个包含单个字段的自定义数据类型:

import Data.Set (Set)

data GraphEdge a = GraphEdge (Set a)

定义我自己的类型感觉在语义上更正确,但它导致我的函数中有很多样板.任何时候我想使用内置Set函数,我必须打开内部集合,然后重新包装它:

import Data.Set (map)

modifyItemsSomehow :: Ord a => GraphEdge a -> GraphEdge a
modifyItemsSomehow (GraphEdge items) = GraphEdge $ Set.map someFunction items

这可以通过使其成为记录来略微改善,例如

import Data.Set (Set, map)

data GraphEdge a = GraphEdge { unGraphEdge :: Set a }

modifyItemsSomehow = GraphEdge . map someFunction . unGraphEdge

但这仍然远非理想.在处理由单个字段组成的用户定义数据类型时,处理此类样板的最惯用方法是什么?



1> András Kovác..:

在其他任何事情之前,您应该确保使用newtype单字段单构造函数类型.data引入运行时开销和额外的懒惰,并阻止我们使用以下两种技术.

首先,您可以GeneralizedNewtypeDeriving尽可能使用:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype Foo a = Foo a deriving (Eq, Show, Ord, Num)

foo :: Foo Int
foo = 0

bar :: Foo Int
bar = foo * 120

其次,您可以使用coerce通常在newtype包装之间进行转换:

import Data.Coerce

newtype Foo a = Foo a
newtype Bar a = Bar a

a :: [(Foo (Bar Int), Foo ())]
a = [(Foo (Bar 0), Foo ())]

b :: [(Int, ())]
b = coerce a

第三,你可以使用iso-s from lens来简单地在newtype构造函数之上/之下移动操作.

{-# LANGUAGE TemplateHaskell #-}

import Data.Set (Set)
import qualified Data.Set as Set
import Control.Lens

newtype GraphEdge a = GraphEdge (Set a)
makePrisms ''GraphEdge

modifyItemsSomehow :: Ord a => GraphEdge a -> GraphEdge a
modifyItemsSomehow = _GraphEdge %~ Set.map someFunction

推荐阅读
地之南_816
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有