微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

学习 Purescript,一些帮助定义类型

如何解决学习 Purescript,一些帮助定义类型

我是函数式编程的新手。我使用过一些 Ramda(JavaScript 库),但与 PureScript 中的类型系统完全不同。

我有一个想法,我觉得应该可以用 PureScript 的类型系统来表达,但我不确定从哪里开始。

假设我正在尝试为数独板定义一些类型

newtype Index = Index Int
newtype Column = Column Int
newtype Row = Row Int
newtype Box = Box Int

我想定义这些类型的加法

在sudocode中:

indexAddition :: (Index | Int) -> (Index | Int) -> Index
indexAddition a b = (a + b) % 81

RowAddition :: (Row | Int) -> (Row | Int) -> Row
RowAddition a b = (a + b) % 9

ColumnAddition 和 BoxAddition 可能我可以与 RowAddition 合并,因为它们将基本相同。

-- I have to be able to say that a is a subset of Int,but Int isn't a type class
FooAddition ::  forall a. Int a => a -> a -> a
FooAddition a b = (a + b) % 9

不知何故,我觉得我很可能在这里走错了路。

有什么帮助吗?

解决方法

为了直接回答您的问题,让函数适用于不同类型的方法是类型类。更具体地说,这样的函数应该是一个类型类的方法,然后你为每个你想要使用的类型(或类型的组合)创建一个实例。

所以最直接的方法是:

class IndexAddition a b where
  indexAddition :: a -> b -> Index
instance addIntInt :: IndexAddition Int Int where
  indexAddition a b = Index ((a+b) % 81)
instance addIntIndex :: IndexAddition Int Index where
  indexAddition a (Index b) = Index ((a+b) % 81)
instance addIndexInt :: IndexAddition Index Int where
  indexAddition (Index a) b = Index ((a+b) % 81)
instance addIndexIndex :: IndexAddition Index Index where
  indexAddition (Index a) (Index b) = Index ((a+b) % 81)

如您所见,我创建了四个实例,一个用于 IndexInt 的每个组合。这有效,但无可否认有点复杂。特别是如果您添加第三个参数或第三种可能的类型。

为了使其更短且更易于管理,您可能会注意到,为了添加特定类型,您只需要一种将它们转换为 Int 的方法。如果有,您可以将两个参数都转换为 Int,然后添加,然后包裹在 Index 中:

class IsInt a where toInt :: a -> Int
instance ciIndex :: IsInt Index where toInt (Index a) = a
instance ciInt :: IsInt Int where toInt a = a

indexAddition :: forall a b. IsInt a => IsInt b => a -> b -> Index
indexAddition a b = Index ((toInt a + toInt b) % 81)

也就是说,我强烈建议您重新考虑您的设计。当然,以任何组合添加数字和索引的能力乍一看可能看起来整洁漂亮,但在实践中您可能永远不需要它。即使您在某些非常特定的情况下这样做,也很容易根据需要包装/解开这些值。相信我,我去过那里。很多次。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。