我有几个问题
我写了一个叫做rope的构造函数,就像这样
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
deriving Show
首先,当我像这样创建TextRope
*Main> let s =TextRope "why"
*Main> s
TextRope {ropeText = "why"}
*Main>
当我执行s时,我只想获得构造函数的字符串,这就是为什么我不太确定。
对concat和sub构造函数也很好奇。具体来说,在我看来你调用了这两个构造函数确实发生了一些事情,你返回了将rope 1和rope 2连接在一起的结果,我不知道在这个语言中该怎么描述,你定义了数据结构但它的返回结果必须由结构
计算出来下面是一些关于这些函数如何工作的例子
> let tr = TextRope "Hello,"
> let sr = TextRope " world!"
> let hw = ConcatRope tr sr
> let ow = SubRope hw 4 4
> tr
Hello,
> sr
world!
> hw
Hello, world!
总的来说有点混乱,对于haskell构造函数和数据类型来说是新的,所以一些指针会有所帮助(虽然不是c指针!)
数据构造函数从来不工作。它们只保存你传递给它们的数据。如果想要完成工作,应该定义所谓的智能构造函数,它们只是在将操作传递给实际构造函数之前执行一些操作的函数。例如
data Fraction = Fraction
{ numerator :: Int
, denominator :: Int
} deriving (Eq)
(%) :: Int -> Int -> Fraction
x % y =
let (a, b) = reduce x y
in Fraction a b
-- Reduces a fraction to it's simplest terms
reduce :: Int -> Int -> (Int, Int)
reduce num den = undefined
这里你不会从你的模块中导出Fraction
构造函数,只导出%
函数,它以最简化的形式构造一个。
您遇到的另一个问题是您希望构造函数以不同的方式输出。你可以通过不推导Show
来达到这个目的。但是,我要警告的是,Haskell约定是show . read = read . show = id
,它不适合您想要做的事情。不过,这并不是一个严格的约定,没有什么可以阻止您这样做:
data Rope = <your implementation minus the deriving Show bit>
instance Show Rope where
show (TextRope t) = t
show (ConcatRope r1 r2) = show r1 ++ show r2
show (SubRope r starting ending) = <exercise left to reader>
作为题外话,我建议不要使用具有不同字段名称的sum类型的记录,这可能会导致您的程序类型检查但包含错误的问题,如果编写不同,则可以在编译时捕获这些错误。例如,如果代码
> ropeText (ConcatRope (TextRope "Hello, ") (TextRope "world!"))
这会导致错误并使程序崩溃!相反,看起来您只需要一个具有concat
和subRope
函数的Rope
类型,因此您可以非常简单地将其实现为
data Rope = Rope String deriving (Eq)
concatRope :: Rope -> Rope -> Rope
concatRope (Rope r1) (Rope r2) = Rope (r1 ++ r2)
-- Why use Integer instead of Int? You might find it's easier to implement this function
subRope :: Rope -> Integer -> Integer -> Rope
subRope (Rope r) start end = Rope $ substr start end r
where substr s e text = <exercise left to reader>
现在绝对没有办法进行非法的rope操作,唯一的区别是现在你必须使用concatRope
代替ConcatRope
和subRope
代替SubRope
。你可以保证这些函数会做你想做的事情,你不会有一些复杂的类型,无论如何都不能帮助你。
如果你不实现你自己的节目(不使用自动派生),你将很难得到你想要的。
但是如果你这样做,这很简单:
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
instance Show Rope where
show (TextRope s) = s
show (ConcatRope a b) = show a ++ show b
我相信你会找到SubRope
情况下自己的实现;)
您的示例代码和示例交互结果不匹配。这就是您如何定义Rope
:
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
deriving Show
deriving Show
部分是关键;我们将看到如何。
之后显示这个示例输出:
> let tr = TextRope "Hello,"
> let sr = TextRope " world!"
> let hw = ConcatRope tr sr
> hw
Hello, world!
对于我刚才展示的代码,实际上,您将看到如下内容:
> hw
ConcatRope { rope1 = TextRope "Hello,", rope2 = TextRope " world!" }
我们可以得到你所描述的输出的唯一方法是,如果我们在你的Rope
定义中去掉deriving Show
子句,并这样写:
instance Show Rope where
show (TextRope text) = text
show (ConcatRope r1 r2) = show r1 ++ show r2
show (SubRope rope start end) = ...