English 中文(简体)
1. 扩大Haskell数据型
原标题:Expand Haskell datatypes

是否可能以新的价值扩大数据类型?

E.g.: The following compiles:

data Axes2D = X | Y
data Axes3D = Axes2D | Z

但如下:

data Axes2D = X | Y deriving (Show, Eq)
data Axes3D = Axes2D | Z deriving (Show, Eq)

type Point2D = (Int, Int)
type Point3D = (Int, Int, Int)

move_along_axis_2D :: Point2D -> Axes2D -> Int -> Point2D
move_along_axis_2D (x, y) axis move | axis == X = (x + move, y)
                                    | otherwise = (x, y + move)

move_along_axis_3D :: Point3D -> Axes3D -> Int -> Point3D
move_along_axis_3D (x, y, z) axis move | axis == X = (x + move, y, z)
                                       | axis == y = (x, y + move, z)
                                       | otherwise = (x, y, z + move) 

(move_along_axis_3D) 评注没有给出错误:

Prelude> :l expandTypes_test.hs 
[1 of 1] Compiling Main             ( expandTypes_test.hs, interpreted )

expandTypes_test.hs:12:50:
    Couldn t match expected type `Axes3D  with actual type `Axes2D 
    In the second argument of `(==) , namely `X 
    In the expression: axis == X
    In a stmt of a pattern guard for
                 an equation for `move_along_axis_3D :
          axis == X
Failed, modules loaded: none.

So is it possible to make X and Y of type Axes2D as well of type Axes3D? If it is possible: what am I doing wrong? Else: why is it not possible?

最佳回答

除了丹尼尔·菲舍尔所说的话外,还不可能在why上扩大:你想要的那种补贴问题比仅仅指点模糊不清更深;因此,一般而言,这种类型的推论更为困难。 我认为,由于这一原因,Schala的这种推论比Haskell更受限制,更当地。

但是,你可以将此类事情与分类系统结合起来:

class (Eq t) => HasAxes2D t where
  axisX :: t
  axisY :: t

class (HasAxes2D t) => HasAxes3D t where
  axisZ :: t

data Axes2D = X | Y deriving (Eq, Show)
data Axes3D = TwoD Axes2D | Z deriving (Eq, Show)

instance HasAxes2D Axes2D where
  axisX = X
  axisY = Y

instance HasAxes2D Axes3D where
  axisX = TwoD X
  axisY = TwoD Y

instance HasAxes3D Axes3D where
  axisZ = Z

之后,你可以使用警卫人员,就这些价值观进行“家长-事项”:

displayAxis :: (HasAxes2D t) => t -> String
displayAxis axis
  | axis == axisX = "X"
  | axis == axisY = "Y"
  | otherwise = "Unknown"

这有许多与次配对相同的缺点:使用<条码>轴/代码>、<条码>xisY和<条码>轴心的倾向将变得模糊不清,要求打上标语的类型说明。 与使用具体类型相比,它还算出一种公平的借方,用这些类型的限制书写签名。

There s another downside: with the concrete types, when you write a function taking an Axes2D, once you handle X and Y you know that you ve covered all possible values. With the type-class solution, there s nothing stopping you from passing Z to a function expecting an instance of HasAxes2D. What you really want is for the relation to go the other way around, so that you could pass X and Y to functions expecting a 3D axis, but couldn t pass Z to functions expecting a 2D axis. I don t think there s any way to model that correctly with Haskell s type-class system.

这种技术有时是有用的——例如,将全球倡议工具包等内容约束为Haskell的欧佩组织图书馆——但一般而言,使用具体类型较为自然,并明确赞成在欧佩组织术语中所说的内容:/composition overmain><>>>,即明确将“替代物”列入构造者。 通常,处理施工包料/un料的双管都不算多,而且除此以外,它还更加灵活。

问题回答

是不可能的。 注

data Axes2D = X | Y
data Axes3D = Axes2D | Z

<代码>Axes2D,载于。 类型为无论据的价值构造者,例如有两个构造者,Axes2DZ

不同类型不可能有名称相同的价值建筑商(范围相同),因为这样便不可能有类型的推论。 什么

foo X = True
foo _ = False

是否有一类? (所有<代码>5be a都有名称相同的价值构造者,该数值与参数类型不同。) 但是,由于<代码>Maybe 采用了一种参数,因此这些名称只在与同一(非普通)类型构造相同的类型之间分配。 它对无固定类型建筑商而言没有工作。

你们可以采用普通的阿尔吉布拉数据类型。 我们可以创建一种通用型(GADT)类型,其数据构造具有类型的限制。 然后,我们可以界定专门类型(种类的别类),具体指明了所有类型,从而限制允许建筑商的种类。

{-# LANGUAGE GADTs #-}

data Zero
data Succ a

data Axis a where
  X :: Axis (Succ a)
  Y :: Axis (Succ (Succ a))
  Z :: Axis (Succ (Succ (Succ a)))

type Axis2D = Axis (Succ (Succ Zero))
type Axis3D = Axis (Succ (Succ (Succ Zero)))

现在,只有<代码>X和Y通过,成为一种职务,界定该职务为:<代码>Axis2D。 构造人<代码>Z与<代码>Axis2D的类型不符。

遗憾的是,GADTs不支持自动<代码>衍生<>/代码>,因此,你需要提供自己的事例,例如:

instance Show (Axis a) where
  show X = "X"
  show Y = "Y"
  show Z = "Z"
instance Eq (Axis a) where
  X == X = True
  Y == Y = True
  Z == Z = True
  _ == _ = False




相关问题
Euler Problem in Haskell -- Can Someone Spot My Error

I m trying my hand at Euler Problem 4 in Haskell. It asks for that largest palindrome formed by multiplying two three-digit numbers. The problem was simple enough, and I thought my Haskell-fu was up ...

How does foldr work?

Can anybody explain how does foldr work? Take these examples: Prelude> foldr (-) 54 [10, 11] 53 Prelude> foldr (x y -> (x+y)/2) 54 [12, 4, 10, 6] 12.0 I am confused about these executions....

Efficient queue in Haskell

How can I efficiently implement a list data structure where I can have 2 views to the head and end of the list, that always point to a head a tail of a list without expensive calls to reverse. i.e: ...

Problem detecting cyclic numbers in Haskell

I am doing problem 61 at project Euler and came up with the following code (to test the case they give): p3 n = n*(n+1) `div` 2 p4 n = n*n p5 n = n*(3*n -1) `div` 2 p6 n = n*(2*n -1) p7 n = n*(5*n -3)...

Ways to get the middle of a list in Haskell?

I ve just started learning about Functional Programming, using Haskel. I m slowly getting through Erik Meijer s lectures on Channel 9 (I ve watched the first 4 so far) and in the 4th video Erik ...

haskell grouping problem

group :: Ord a => [(a, [b])] -> [(a, [b])] I want to look up all pairs that have the same fst, and merge them, by appending all the list of bs together where they have the same a and discarding ...

Closest equivalent to subprocess.communicate in Haskell

I want to do a popen() / python s subprocess.communicate from Haskell - start a program, give it stdin, and get its stdout/stderr. What s the most direct / Haskellish way to do this?