如何在不重复Haskell中的代码的情况下创建多种有界类型? [英] How to create many bounded types without duplicating code in Haskell?

查看:169
本文介绍了如何在不重复Haskell中的代码的情况下创建多种有界类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于一个项目,我创建了一个基于Int的类型,只要程序尝试使用超出限制的值(在我的情况下为[0..127]),就会抛出错误。下面的代码实现了这一点,它适用于我。



Haskell有可能创建第二个有界类型(例如[0..255]),而不会重复这段代码?



感谢您的回答

  { - #LANGUAGE GeneralizedNewtypeDiving# - } 
模块Minitel.Type.MNatural(MNat,mnat,fromMNat)其中

- | MNat类型。构造函数是隐藏的。
newtype MNat = MakeMNat Int推导(真实,Eq,Ord,显示)

- | MNat是有界类型
实例有界MNat其中
minBound = MakeMNat 0
maxBound = MakeMNat 127

- |将Int转换为MNat
mnat :: Int - > MNat
mnat x | loLimit< = x&& x <= hiLimit = MakeMNat x
|否则=错误Number out of bounds
其中loLimit = fromIntegral(minBound :: MNat)
hiLimit = fromIntegral(maxBound :: MNat)

- 将MNat从MNat :: MNat转换为Int
- > Int
fromMNat(MakeMNat i)= i

- |将返回Int的Int二进制函数转换为MNat二进制函数
- 返回MNat
mfnat ::(Int→> Int) - > (MNat - > MNat)
mfnat f = mnat。 F 。 fromMNat

mfnat2 ::(Int - > Int - > Int) - > (MNat - > MNat - > MNat)
mfnat2 f x y = mnat $ f(fromMat x)(fromMat y)

- 你可以用MNat
实例Num MNat进行加法,减法和乘法运算,其中
fromInteger = mnat。从整数
(+)= mfnat2(+)
( - )= mfnat2( - )
(*)= mfnat2(*)
abs = mfnat abs
signum = mfnat signum

- |允许使用toInteger和MNat
实例Integral MNat其中
quotRem xy =(fromInteger $ quot x'y',fromInteger $ rem x'y')
其中(x',y') =(toInteger x,toInteger y)
toInteger = toInteger。 fromMNat

- |允许生成列表
实例Enum MNat其中
toEnum = mnat
fromEnum = fromMNat

注意:


  • 表现并不重要

$ b $你可以在GHC 7.8中使用类型级文字来完成它:

  { - #LANGUAGE DataKinds,PolyKinds,ScopedTypeVariables# - } 
模块SO26723035其中

导入GHC.TypeLits
导入Data.Proxy

newtype MNat(n :: Nat)= MakeMNat Int派生(Eq,Ord,Show)

实例KnownNat n =>有界(MNat n)其中
minBound = MakeMNat 0
maxBound = MakeMNat。 fromInteger $ natVal(Proxy :: Proxy n)

 

  ghci> maxBound :: MNat 5 
MakeMNat 5

您可以使用类型同义词修复单个类型。剩下的代码用这个多态 MNat 和机械变化编译。您必须随处添加 KnownNat 上下文,并在 mnat ScopedTypeVariables c>。


For a project, I’ve created a type based on Int which throws an error whenever the program tries to use a value beyond limits ([0..127] in my case). The code below does this and it works for me.

Is it possible in Haskell to create a second bounded type (say [0..255] for example) without duplicating this code ?

Thanks for your answers

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Minitel.Type.MNatural (MNat, mnat, fromMNat) where

-- | The MNat type. The constructor is hidden.
newtype MNat = MakeMNat Int deriving (Real, Eq, Ord, Show)

-- | MNat is a bounded type
instance Bounded MNat where
    minBound = MakeMNat 0
    maxBound = MakeMNat 127

-- | Converts an Int into an MNat
mnat :: Int -> MNat
mnat x | loLimit <= x && x <= hiLimit = MakeMNat x
       | otherwise = error "Number out of bounds"
       where loLimit = fromIntegral (minBound :: MNat)
             hiLimit = fromIntegral (maxBound :: MNat)

-- | Converts an MNat into an Int
fromMNat :: MNat -> Int
fromMNat (MakeMNat i) = i

-- | Converts an Int binary function returning Int to a MNat binary function
--   returning an MNat
mfnat :: (Int -> Int) -> (MNat -> MNat)
mfnat f = mnat . f . fromMNat

mfnat2 :: (Int -> Int -> Int) -> (MNat -> MNat -> MNat)
mfnat2 f x y = mnat $ f (fromMNat x) (fromMNat y)

-- | You can do additions, substractions and multiplication with MNat
instance Num MNat where
    fromInteger = mnat . fromIntegral
    (+)         = mfnat2 (+)
    (-)         = mfnat2 (-)
    (*)         = mfnat2 (*)
    abs         = mfnat abs
    signum      = mfnat signum

-- | Allows to use toInteger with MNat
instance Integral MNat where
    quotRem x y = (fromInteger $ quot x' y', fromInteger $ rem x' y')
                  where (x', y') = (toInteger x, toInteger y)
    toInteger   = toInteger . fromMNat

-- | Allows to generate lists
instance Enum MNat where
    toEnum      = mnat
    fromEnum    = fromMNat

Note:

  • performance is not a matter here

解决方案

You can do it in GHC 7.8 using type-level literals:

{-# LANGUAGE DataKinds, PolyKinds, ScopedTypeVariables #-}
module SO26723035 where

import GHC.TypeLits
import Data.Proxy

newtype MNat (n :: Nat) = MakeMNat Int deriving (Eq, Ord, Show)

instance KnownNat n => Bounded (MNat n) where
  minBound = MakeMNat 0
  maxBound = MakeMNat . fromInteger $ natVal (Proxy :: Proxy n)

 

ghci> maxBound :: MNat 5
MakeMNat 5

You can use type synonyms to fix individual types. The rest of your code compiles fine with this polymorphic MNat with mechanical changes. You have to add the KnownNat context everywhere and use ScopedTypeVariables in mnat.

这篇关于如何在不重复Haskell中的代码的情况下创建多种有界类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆