这个haskell样本能缩短吗?

Dmi*_*rov 5 haskell

这是我从YAHT练习的解决方案:

练习4.6编写一个数据类型元组,它可以包含一个,两个,三个或四个元素,具体取决于构造函数(也就是说,应该有四个构造函数,每个参数个数一个).还提供了tuple1到tuple4的函数,它们取一个元组并返回该位置中的值,如果该数字有效则返回Nothing(即,你只要求元组中的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'

Dan*_*ner 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)
Run Code Online (Sandbox Code Playgroud)

或者,您可以显式表达嵌套结构:

{-# 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
Run Code Online (Sandbox Code Playgroud)

然后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
Run Code Online (Sandbox Code Playgroud)


Lan*_*dei 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
Run Code Online (Sandbox Code Playgroud)