这是我从YAHT行使的解决方案:
练习4.6编写一个数据类型元组,它可以容纳一个,两个,三个或者 四个元素,取决于构造函数(也就是说,应该有 四个构造函数,每个参数数量一个)。还提供 函数tuple1到tuple4,它取一个元组并返回Just 该位置的值,如果该数字有效则无效(即 你在元组中要求tuple4仅包含两个元素。)
当我写第一行时,我对简单与C#相比感到兴奋
data Tuplex a b c d = Tuple1 a | Tuple2 a b | Tuple3 a b c | Tuple4 a b c d -- class Tuplex<a,b,c,d> { -- Tuplex(a p1){ _p1 = p1; } -- Tuplex(a p1, b p2){ _p1 = p1; _p2 = p2; } -- Tuplex(a p1, b p2, c p3){ _p1 = p1; _p2 = p2; _p3 = p3; } -- Tuplex(a p1, b p2, c p3, d p4){ _p1 = p1; _p2 = p2; _p3 = p3; _p4 = p4; } -- public Nullable<a> _p1; -- public Nullable<b> _p2; -- public Nullable<c> _p3; -- public Nullable<d> _p4; -- }
在C#中我可以毫无问题地访问任何字段,但在这里我应该写一个“访问者函数”,对吧?这里的代码数量让我感到难过。
我可以在这里使用更短的代码吗?
tuple1 ∷ Tuplex a b c d → Maybe a tuple2 ∷ Tuplex a b c d → Maybe b tuple3 ∷ Tuplex a b c d → Maybe c tuple4 ∷ Tuplex a b c d → Maybe d tuple1 (Tuple1 a) = Just a tuple1 (Tuple2 a b) = Just a tuple1 (Tuple3 a b c) = Just a tuple1 (Tuple4 a b c d) = Just a tuple2 (Tuple1 a) = Nothing tuple2 (Tuple2 a b) = Just b tuple2 (Tuple3 a b c) = Just b tuple2 (Tuple4 a b c d) = Just b tuple3 (Tuple1 a) = Nothing tuple3 (Tuple2 a b) = Nothing tuple3 (Tuple3 a b c) = Just c tuple3 (Tuple4 a b c d) = Just c tuple4 (Tuple1 a) = Nothing tuple4 (Tuple2 a b) = Nothing tuple4 (Tuple3 a b c) = Nothing tuple4 (Tuple4 a b c d) = Just d -- unit tests prop_tx1 = tuple1 (Tuple1 4) ≡ Just 4 prop_tx2 = tuple1 (Tuple2 4 'q') ≡ Just 4 prop_tx3 = tuple2 (Tuple1 4) ≡ (Nothing ∷ Maybe Char) prop_tx4 = tuple2 (Tuple2 4 'q') ≡ Just 'q'
答案 0 :(得分:7)
这是一种方法:集中你的模式匹配。
unTuplex f1 f2 f3 f4 t = case t of
Tuple1 a -> f1 a
Tuple2 a b -> f2 a b
Tuple3 a b c -> f3 a b c
Tuple4 a b c d -> f4 a b c d
tuple1 = unTuplex (\a -> Just a ) (\a _ -> Just a ) (\a _ _ -> Just a ) (\a _ _ _ -> Just a)
tuple2 = unTuplex (\_ -> Nothing) (\_ b -> Just b ) (\_ b _ -> Just b ) (\_ b _ _ -> Just b)
tuple3 = unTuplex (\_ -> Nothing) (\_ _ -> Nothing) (\_ _ c -> Just c ) (\_ _ c _ -> Just c)
tuple4 = unTuplex (\_ -> Nothing) (\_ _ -> Nothing) (\_ _ _ -> Nothing) (\_ _ _ d -> Just d)
或者,您可以明确表达嵌套结构:
{-# LANGUAGE NoMonomorphismRestriction #-}
data DONE = DONE -- could just use (), but this is a pretty descriptive name
type Tuplex a b c d = Maybe (a, Maybe (b, Maybe (c, Maybe (d, DONE))))
tuple1 x = x >>= return . fst -- or tuple1 = fmap fst
tuple2 x = x >>= tuple1 . snd
tuple3 x = x >>= tuple2 . snd
tuple4 x = x >>= tuple3 . snd
然后tuple1
有({等等)类型Tuplex a b c d -> Maybe a
,最高为tuple4
,其中{再次,等等)类型为Tuplex a b c d -> Maybe d
。
编辑:......实际上,这表明第一种方法的另一种延续。
import Control.Monad
decrement :: Tuplex a b c d -> Maybe (Tuplex b c d t)
decrement (Tuple1 a) = Nothing
decrement (Tuple2 a b) = Just (Tuple1 b)
decrement (Tuple3 a b c) = Just (Tuple2 b c)
decrement (Tuple4 a b c d) = Just (Tuple3 b c d)
zero :: Tuplex a b c d -> a
zero (Tuple1 a) = a
zero (Tuple2 a b) = a
zero (Tuple3 a b c) = a
zero (Tuple4 a b c d) = a
tuple1 = Just . zero
tuple2 = decrement >=> tuple1
tuple3 = decrement >=> tuple2
tuple4 = decrement >=> tuple3
答案 1 :(得分:7)
我会尽量保持简单:
data Tuplex a b c d = Tuple1 a | Tuple2 a b | Tuple3 a b c | Tuple4 a b c d
toMaybes (Tuple1 p) = (Just p, Nothing, Nothing, Nothing)
toMaybes (Tuple2 p q) = (Just p, Just q, Nothing, Nothing)
toMaybes (Tuple3 p q r) = (Just p, Just q, Just r, Nothing)
toMaybes (Tuple4 p q r s) = (Just p, Just q, Just r, Just s)
tuple1 t = p where (p,_,_,_) = toMaybes t
tuple2 t = q where (_,q,_,_) = toMaybes t
tuple3 t = r where (_,_,r,_) = toMaybes t
tuple4 t = s where (_,_,_,s) = toMaybes t
答案 2 :(得分:1)
只需给你的元组字段名称!
data Tuplex a b c d = Tuple1 { tuple1 :: a }
| Tuple2 { tuple1 :: a
, tuple2 :: b }
| Tuple3 { tuple1 :: a
, tuple2 :: b
, tuple3 :: c }
| Tuple4 { tuple1 :: a
, tuple2 :: b
, tuple3 :: c
, tuple4 :: d }
因此,您可以使用以下类型的函数:
tuple1 :: Tuplex a b c d -> a
tuple2 :: Tuplex a b c d -> b
-- etc
使用这样的记录的字段名称实际上不像Haskell中那样常见,因为模式匹配很容易,并且至少在某些圈子中,RecordWildCard
扩展名的流行度允许你做比如:
function (Tuples3 {..}) =
-- now you have variables tuple1 :: a, tuple2 :: b, etc.
(当使用记录通配符时,最好将元组字段命名为更简单的东西,如tupA,tupB,tupC,tupD)
答案 3 :(得分:1)
import Safe (atMay) -- from the 'safe' package
toList (Tuple1 a) = [a]
toList (Tuple2 a b) = [a, b]
toList (Tuple3 a b c) = [a, b, c]
toList (Tuple4 a b c d) = [a, b, c, d]
tuple n t = atMay (toList t) n
[tuple1, tuple2, tuple3, tuple4] = map tuple [1..4]
编辑:Vitus正确地指出这只适用于同类元组,所以这不是一个正确的答案。在那种情况下,我会顺从丹尼尔的回答。