Haskell类型的具体数据构造函数

问题描述 投票:0回答:4

SO是一场狗屎秀。感谢您的搭车。

haskell types constructor
4个回答
5
投票

您可以使用 GADTs 为此。

{-# LANGUAGE GADTs #-}

data Option a where
    Help :: Option ()
    Opt1 :: Int -> Double -> String -> Option (Int, Double, String)

handleOption :: Option a -> IO ()
handleOption option = case option of
    Help          -> handleHelp
    opt1 @ Opt1{} -> handleOpt1 opt1

handleHelp :: IO ()
handleHelp = print "help"

handleOpt1 :: Option (Int, Double, String) -> IO ()
handleOpt1 (Opt1 n f s) = print (n, f, s)

使用 GADT,您可以向编译器提供更多类型信息。对于

handleOpt1
,由于它只接受
Option (Int, Double, String)
,编译器知道
Option ()
(即
Help
)永远不会被传入。

也就是说,使用 GADT 会让很多其他事情变得更加困难。例如,自动派生(例如

deriving (Eq, Show)
)通常不适用于它们。您应该仔细考虑在您的情况下使用它们的利弊。


2
投票

在这个特定的例子中,通过抛弃

handleHelp
handleOpt1
并使它们成为
handleOption
函数的独立方程来解决“问题”似乎更自然:

handleOption :: Option -> IO ()

handleOption Help = print "help"

handleOption (Opt1 n f s) = print (n, f, s)

这让您两全其美。您可以为每种情况编写一个单独的方程(因此,即使每个案例很大,您也可以防止它们合并成一个巨大的方程),您不必编写任何样板“调度”函数,也不必说出

Opt1
外壳的各个部分的名称,直到您真正需要使用它们为止。


2
投票

GHC 内联

handleHelp
handleOpt1
的可能性很大,从而避免了调用开销 - 查看生成的 Core(编译器的中间表示)以确定答案。

如果由于某种原因,这些函数没有被内联,您可以用 INLINE

 pragma
:

标记它们
handleHelp :: IO ()
handleHelp = print "help"
{-# INLINE handleHelp #-}

handleOpt1 :: Option -> IO ()
handleOpt1 (Opt1 n f s) = print (n, f, s)
{-# INLINE handleOpt1 #-}

您还可以依靠内联函数来避免解构

handleOption
中的参数:

handleOpt1 :: Option -> IO ()
handleOpt1 (Opt1 n f s) = print (n, f, s)
handleOpt1 _ = undefined

undefined
只是为了消除有关非详尽模式匹配的警告。或者,您可以删除此行并为此模块启用
-fno-warn-incomplete-patterns

查看生成的Core,我们可以看到

undefined
handleOpt1
分支被消除了:

handleOpt2
  :: Option
     -> State# RealWorld
     -> (# State# RealWorld, () #)
handleOpt2 =
  \ (ds_dl7 :: Option)
    (eta_Xh :: State# RealWorld) ->
    case ds_dl7 of _ {
      Help -> ...  
      Opt1 n_aaq f_aar s_aas -> ...

main1
  :: State# RealWorld
     -> (# State# RealWorld, () #)
main1 =
  \ (eta_Xk :: State# RealWorld) ->
    handleOpt2 (Opt1 2 3.0 "") eta_Xk

不过,我更喜欢原始版本,因为它排除了

handleOpt1
中模式匹配失败的可能性。


0
投票

我喜欢 Ben 的回答,但或者,你也可以引入更多类型。

数据 Opt1Params = Opt1Params Int 双字符串

数据选项 = 帮助 | Opt1 Opt1Params

handleOption帮助=handleHelp handleOption(Opt1 参数)=handleOpt1 参数

handleOpt1 (Opt1Params n f s) = ...

© www.soinside.com 2019 - 2024. All rights reserved.