Haskell中案例的较短语法?

Haskell中案例的较短语法?,haskell,Haskell,比如说我有这样愚蠢的事情: data SomeType = Unary Int | Associative SomeType | Binary SomeType SomeType some_func :: SomeType -> Int some_func s = case s of Unary n -> n Associative s1 -> some_func s1 Binary s1 s2

比如说我有这样愚蠢的事情:

data SomeType
    = Unary Int
    | Associative SomeType
    | Binary SomeType SomeType

some_func :: SomeType -> Int
some_func s =
    case s of
        Unary n -> n
        Associative s1 -> some_func s1
        Binary s1 s2 -> some_func s1 + some_func s2
data SomeType
    = Unary Int
    | Associative SomeType
    | Binary SomeType SomeType

some_func :: SomeType -> Int
some_func s =
    case s of
        Unary n -> n
        Associative s1 -> sf1
        Binary s1 s2 -> sf1 + sf2
        where
            sf1 = some_func s1
            sf2 = some_func s2
这里有些函数将检查给定SomeType中的所有SomeType,并总结所有一元数据构造函数的整数。SomeType是一种递归数据类型

在这些模式匹配中,我重复了
一些函数s1
。有没有一种方法可以使用@、when、let或其他任何东西来声明
sf1=some_func s1
并在两者中都使用它?大概是这样的:

data SomeType
    = Unary Int
    | Associative SomeType
    | Binary SomeType SomeType

some_func :: SomeType -> Int
some_func s =
    case s of
        Unary n -> n
        Associative s1 -> some_func s1
        Binary s1 s2 -> some_func s1 + some_func s2
data SomeType
    = Unary Int
    | Associative SomeType
    | Binary SomeType SomeType

some_func :: SomeType -> Int
some_func s =
    case s of
        Unary n -> n
        Associative s1 -> sf1
        Binary s1 s2 -> sf1 + sf2
        where
            sf1 = some_func s1
            sf2 = some_func s2

这里的问题是s1和s2只在
->
之后的块中已知,无法计算sf1。

答案是否定的:
Associative
中的
s1
Binary
中的
s1
不同。他们同名的事实是一种干扰,因为他们存在于不同的环境中

我想您可以通过使用助手来节省一些输入,但这并不能真正帮助封装重复的逻辑:

some_func :: SomeType -> Int
some_func s = go s
  where go (Unary n) = n
        go (Associative s1) = go s1
        go (Binary s1 s2) = go s1 + go s2

我不确定这是否会使它在这个特定的情况下更短,但在更一般的情况下,你应该检查。例如:

{-# LANGUAGE Rank2Types, DeriveDataTypeable, NoMonomorphismRestriction #-}

import Data.Generics

data SomeType
    = Unary Int
    | Associative SomeType
    | Binary SomeType SomeType
    deriving (Data, Typeable, Show)

flatten_sometype x@(Unary _) = x
flatten_sometype (Associative s) = s
flatten_sometype (Binary (Unary a) (Unary b)) = Unary $ a + b

some_func2 = let Unary n = everywhere (mkT flatten_sometype)
             in  n

正如您所看到的,通过在所有地方使用
,我只需要指定一个局部转换-SYB负责所有递归。当你有多种类型参与时,这真的很有用;SYB会很高兴地穿越你没有转换的类型,并转换它们的参数。但要注意使用量——如果使用过度,可能会导致大量GC流失。

这并不能回答问题,但可能会解决问题:

{-# LANGUAGE DeriveFoldable #-}
module SomeType where
import Data.Foldable as F

data SomeType a
    = Unary a
    | Associative (SomeType a)
    | Binary (SomeType a) (SomeType a)
      deriving (Foldable)

some_func :: SomeType Int -> Int
some_func = F.foldl1 (+)

编写它的最短方法应该是模式匹配:

some_func :: SomeType -> Int
some_func (Unary n) = n
some_func (Associative s) = some_func s
some_func (Binary s1 s2) = (some_func s1) + (some_func s2)
仍然有重复的片段,所以它可能无法回答您的问题。。。可能涉及定义
some\u func
,即
fmap some\u func

滥用记录语法

data SomeType
    = Unary { u :: Int }
    | Associative { s1 :: SomeType }
    | Binary { s1, s2 :: SomeType }

someFunc :: SomeType -> Int
someFunc s = case s of
    Unary{}       -> u s
    Associative{} -> sf1
    Binary{}      -> sf1 + sf2
  where
    sf1 = someFunc (s1 s)
    sf2 = someFunc (s2 s)

请注意,相同类型的不同构造函数允许在其记录中具有相同的命名字段。懒惰可以防止你在
sf2
上出错,如果你在
关联分支上出错。

s1和s2是什么,我看不到它们的定义。你把s作为参数,然后定义只有sf1和sf2.s1和s2是某种类型的,它们来自案例中的模式匹配Flatte_SomeType的类型特征是什么?@AramKocharyan:
SomeType→ SomeType
。但是请注意,它不是全部函数。
some\u func2
的类型也是
SomeType->SomeType
,对吗?而原来的
somefunc
SomeType->Int
。我认为理想的结果是在一元构造函数中?
some\u func s=go s
-我认为在
go
方面写这篇文章没有任何意义,为什么不直接在
some\u func
级别进行模式匹配呢?这只是为了“节省一些打字时间”?我不鼓励使用没有附加值的助手函数,即使它可以节省一些击键次数。@DanBurton,“我猜”是非常不情愿的。我同意这几乎毫无意义。我认为这是最简单、最优雅的解决方案,做得很好。