克隆羊型应如何构建
How should the cloned sheep type be constructed
所以在Haskell monads的解释中他们举了克隆羊的例子。
但是他们只给出了数据类型的部分实现:
type Sheep = ...
father :: Sheep -> Maybe Sheep
father = ...
mother :: Sheep -> Maybe Sheep
mother = ...
这使得试验和理解 comb 等 monad 的用法变得相当困难:
-- comb is a combinator for sequencing operations that return Maybe
comb :: Maybe a -> (a -> Maybe b) -> Maybe b
comb Nothing _ = Nothing
comb (Just x) f = f x
Sheep
应该如何实施?
Sheep
的一个最小实现是
data Sheep = Sheep {mother :: Maybe Sheep, father :: Maybe Sheep}
一个更理智的实现,你可以有兄弟姐妹(可以通过他们的 name
来区分)
data Sheep = Sheep {name :: String, mother :: Maybe Sheep, father :: Maybe Sheep}
这个答案是为了解决您在评论中所做的澄清:
the given definition is of type
and the answer is of data
, which I don't understand yet how this can happen.
Haskell 有几种不同的类型声明方式。
type
关键字用于声明一个类型别名——类似于C++中的typedef
或using
。理论上,作为徒劳的练习,可以将 Sheep
声明为 String
的别名,隐含的理解是 String
表示羊的名字,然后有一个 "global" 每只羊的 parents 列表,mother
和 father
函数将用于查找:
type Sheep = String
allParents :: [(Sheep, (Sheep, Sheep))]
allParents =
[ ("dolly", ("rufus", "peggy"))
, ("peggy", ("ramses", "woolly"))
, ...
]
mother :: Sheep -> Maybe Sheep
mother s = fst <$> lookup s allParents
father :: Sheep -> Maybe Sheep
father s = snd <$> lookup s allParents
但这 非常 不寻常并且根本不起作用。我认为这将是 gorilla holding a banana and the entire jungle.
的主要示例
一种更 Haskell 的情况建模方法是将 Sheep
声明为具有(至少)两个字段的数据结构 - mother
和 father
。对于这种事情,可以使用关键字 data
:
data Sheep = Sheep (Maybe Sheep) (Maybe Sheep)
father :: Sheep -> Maybe Sheep
father (Sheep f _) = f
mother :: Sheep -> Maybe Sheep
mother (Sheep _ m) = m
但是为你的类型的每个字段定义这些访问器函数是很普通的,所以 Haskell 有一个更短的语法:
data Sheep = Sheep { father :: Maybe Sheep, mother :: Maybe Sheep }
这将声明具有两个字段的相同结构,plus 自动创建访问器函数,其工作方式与前面的示例相同。
为了抢占你的下一个问题,我还应该提到第三种定义类型的方法 - newtype
,它类似于 data
,但仅适用于只有一个字段的结构,并且只是一个性能优化。
不要纠结于所使用的特定关键字。这篇文章只需要指出有这种类型和两个函数,它们是如何定义的并不重要。这篇文章不得不用一些关键词来说明这一点,他们选择了type
。或多或少的任意选择。
Sheep
的定义确实无关紧要。 mother
和 father
的定义 使用 重要的定义。以下将起作用
type Sheep = Int
mother :: Sheep -> Maybe Sheep
mother 0 = Nothing
mother 1 = Nothing
mother n = Just (n `div` 2)
father :: Sheep -> MaybeSheep
father 0 = Nothing
father 1 = Nothing
father n = Just (n `mod` 2)
如愿
type Sheep = String
mother :: Sheep -> Maybe Sheep
mother (x:_:rest) = Just [x]
mother _ = Nothing
father :: Sheep -> Maybe Sheep
father (_:x:rest) = Just [x]
father _ = Nothing
(在这两种情况下,我都不太关心 mother
和 father
的意思 ;这一点说明了类型才是最重要的。 )
comb
本身其实并不关心什么mother
和father
return;它只是处理试图找到非绵羊的母亲或父亲的问题。只要类型正确,您就可以将 mother
和 father
与 comb
一起使用。
comb (Just name) mother == mother name -- name :: Sheep, so mother name :: Maybe Sheep
comb Nothing mother == Nothing -- Nothing :: Maybe Sheep in both cases
所以在Haskell monads的解释中他们举了克隆羊的例子。 但是他们只给出了数据类型的部分实现:
type Sheep = ...
father :: Sheep -> Maybe Sheep
father = ...
mother :: Sheep -> Maybe Sheep
mother = ...
这使得试验和理解 comb 等 monad 的用法变得相当困难:
-- comb is a combinator for sequencing operations that return Maybe
comb :: Maybe a -> (a -> Maybe b) -> Maybe b
comb Nothing _ = Nothing
comb (Just x) f = f x
Sheep
应该如何实施?
Sheep
的一个最小实现是
data Sheep = Sheep {mother :: Maybe Sheep, father :: Maybe Sheep}
一个更理智的实现,你可以有兄弟姐妹(可以通过他们的 name
来区分)
data Sheep = Sheep {name :: String, mother :: Maybe Sheep, father :: Maybe Sheep}
这个答案是为了解决您在评论中所做的澄清:
the given definition is of
type
and the answer is ofdata
, which I don't understand yet how this can happen.
Haskell 有几种不同的类型声明方式。
type
关键字用于声明一个类型别名——类似于C++中的typedef
或using
。理论上,作为徒劳的练习,可以将 Sheep
声明为 String
的别名,隐含的理解是 String
表示羊的名字,然后有一个 "global" 每只羊的 parents 列表,mother
和 father
函数将用于查找:
type Sheep = String
allParents :: [(Sheep, (Sheep, Sheep))]
allParents =
[ ("dolly", ("rufus", "peggy"))
, ("peggy", ("ramses", "woolly"))
, ...
]
mother :: Sheep -> Maybe Sheep
mother s = fst <$> lookup s allParents
father :: Sheep -> Maybe Sheep
father s = snd <$> lookup s allParents
但这 非常 不寻常并且根本不起作用。我认为这将是 gorilla holding a banana and the entire jungle.
的主要示例一种更 Haskell 的情况建模方法是将 Sheep
声明为具有(至少)两个字段的数据结构 - mother
和 father
。对于这种事情,可以使用关键字 data
:
data Sheep = Sheep (Maybe Sheep) (Maybe Sheep)
father :: Sheep -> Maybe Sheep
father (Sheep f _) = f
mother :: Sheep -> Maybe Sheep
mother (Sheep _ m) = m
但是为你的类型的每个字段定义这些访问器函数是很普通的,所以 Haskell 有一个更短的语法:
data Sheep = Sheep { father :: Maybe Sheep, mother :: Maybe Sheep }
这将声明具有两个字段的相同结构,plus 自动创建访问器函数,其工作方式与前面的示例相同。
为了抢占你的下一个问题,我还应该提到第三种定义类型的方法 - newtype
,它类似于 data
,但仅适用于只有一个字段的结构,并且只是一个性能优化。
不要纠结于所使用的特定关键字。这篇文章只需要指出有这种类型和两个函数,它们是如何定义的并不重要。这篇文章不得不用一些关键词来说明这一点,他们选择了type
。或多或少的任意选择。
Sheep
的定义确实无关紧要。 mother
和 father
的定义 使用 重要的定义。以下将起作用
type Sheep = Int
mother :: Sheep -> Maybe Sheep
mother 0 = Nothing
mother 1 = Nothing
mother n = Just (n `div` 2)
father :: Sheep -> MaybeSheep
father 0 = Nothing
father 1 = Nothing
father n = Just (n `mod` 2)
如愿
type Sheep = String
mother :: Sheep -> Maybe Sheep
mother (x:_:rest) = Just [x]
mother _ = Nothing
father :: Sheep -> Maybe Sheep
father (_:x:rest) = Just [x]
father _ = Nothing
(在这两种情况下,我都不太关心 mother
和 father
的意思 ;这一点说明了类型才是最重要的。 )
comb
本身其实并不关心什么mother
和father
return;它只是处理试图找到非绵羊的母亲或父亲的问题。只要类型正确,您就可以将 mother
和 father
与 comb
一起使用。
comb (Just name) mother == mother name -- name :: Sheep, so mother name :: Maybe Sheep
comb Nothing mother == Nothing -- Nothing :: Maybe Sheep in both cases