gpt4 book ai didi

haskell - 如何拥有一种具有可索引但可选元素(要求 Haskell 中存在)的类型

转载 作者:行者123 更新时间:2023-12-02 16:56:21 25 4
gpt4 key购买 nike

我需要一个具有一定数量可索引“槽”的类型结构(这样我们就可以分别一致地对槽 1、2 或 3 中的项目使用react)

(Maybe a, Maybe b, Maybe c...) 很笨重,对于框架来说很难做很多事情,并且允许表示 (Nothing, Nothing...) ,这对于我来说是不应该允许的正在做。

这有效:数据 或 a b = 或两者 a b |或左一个 |或者右b

并且具有完全正确的语义,但模式匹配却很困惑。

OrBoth tas1 (OrRight (OrRight new)) ->
OrBoth tas1 (OrRight (OrBoth _ new)) ->
OrBoth tas1 (OrBoth _ (OrRight new)) ->
OrBoth tas1 (OrBoth _ (OrBoth _ new)) ->

关于如何高效且可读地完成此操作还有其他想法吗?

Ed'ka 的回答很好,我还有另一个问题:

是否可以让它创建正确大小的“元组”?

step :: (Nothingable a, Nothingable b) => SignalFunction a b -> a -> (SignalFunction a b, b)
step sf nothing = (sf, nothing) -- second nothing here is error
step sf a = transition sf a

src/Processors.hs:59:23:
Couldn't match expected type `b' against inferred type `a'
`b' is a rigid type variable bound by
the type signature for `step' at src/Processors.hs:58:36
`a' is a rigid type variable bound by
the type signature for `step' at src/Processors.hs:58:21
In the expression: nothing

最佳答案

GADT-s 可以很方便地处理此类事情。不确定这有多实用,但是您可以进行模式匹配,并且它不会允许您传递“空”(全部为“无”)情况。作为“异构集合”Spec 可以是任意长度,并且可以指定不同类型的元素(类似元组)。

{-# LANGUAGE TypeOperators, EmptyDataDecls, GADTs, TypeFamilies #-}

data Empty
data NonEmpty

-- Infix forms of data type and constructor (looks nicer here)
infixr 7 :*:
data a :*: b

-- GADT definition of heterogeneous list
-- with 'e' parameter specifing possible "emptiness" of the result (if all items in the list are 'None')
data Spec a e where
(:*:) :: Spec a e1 -> Spec b e2 -> Spec (a :*: b) (Calc e1 e2)
None :: Spec a Empty
Some :: a -> Spec a NonEmpty


-- Only when two 'Empty' Specs are cons-ed will we get Empty
type family Calc a b
type instance Calc Empty Empty = Empty
type instance Calc Empty NonEmpty = NonEmpty
type instance Calc NonEmpty Empty = NonEmpty
type instance Calc NonEmpty NonEmpty = NonEmpty


-- Example of usage
-- We need to specify the type here (GADT..) and not to forget to add 'NonEmpty'
foo :: Spec (Int :*: Bool :*: Char) NonEmpty -> Int
foo (Some 5 :*: Some _ :*: Some _) = 1
foo (Some _ :*: Some b :*: Some 'c') = if b then 2 else 22
foo (Some 4 :*: None :*: None) = 3
foo (None :*: Some _ :*: None) = 4
foo (None :*: None :*: Some 'a') = 5
foo (Some _ :*: Some _ :*: Some _) = 42

-- Some test cases:
t1 = foo (Some 5 :*: Some True :*: Some 'a') -- ==> 1
t2 = foo (Some 8 :*: Some False :*: Some 'c') -- ==> 22
t3 = foo (Some 4 :*: None :*: None) -- ==> 3
t4 = foo (None :*: Some True :*: None) -- ==> 4
t5 = foo (None :*: Some False :*: None) -- ==> 4
t6 = foo (Some 1 :*: Some True :*: Some 'e') -- ==> 42
-- t7 = foo (None :*: None :*: None) -- Will not compile due to Empty/NonEmpty mismatch (at least one item should be not 'None')

另:http://homepages.cwi.nl/~ralf/HList/ “强类型异构集合”

更新:根据作者的评论:如果我们省略对“all Nothing”情况的静态检查的要求,并随后摆脱 GADT(在使用时确实需要显式类型规范),我们可以使用标准 ADT 加上一些简单的类型级计算来生成“all Nothing”情况动态检查:

{-# LANGUAGE TypeOperators, FlexibleInstances #-}

infixr 7 :*:
data a :*: b = a :*: b

-- type-level manipulations against our "custom-made tuple"
-- for now it only generates a tuple with all members set to Nothing, but can be extended
class Nothingable a where
nothing :: a

instance Nothingable (Maybe a) where
nothing = Nothing
instance (Nothingable b) => Nothingable (Maybe a :*: b) where
nothing = Nothing :*: nothing

-- the same tests
foo (Just 5 :*: Just True :*: Just 'a') = 1
foo (Just _ :*: Just b :*: Just 'c') = if b then 2 else 22
foo (Just 4 :*: Nothing :*: Nothing) = 3
foo (Nothing :*: Just _ :*: Nothing) = 4
foo (Nothing :*: Nothing :*: Just 'a') = 5
foo (Just _ :*: Just _ :*: Just _) = 42
-- test for "all Nothing"
foo nothing = error "Need at least one non 'Nothing' case"

-- works for let and case bindings
boo t =
let (Just a :*: b) = t
in case b of
(Just _ :*: Nothing :*: Just c) -> c
nothing -> 0

t1 = foo (Just 5 :*: Just True :*: Just 'a') -- ==> 1
t2 = foo (Just 8 :*: Just False :*: Just 'c') -- ==> 22
t3 = foo (Just 4 :*: Nothing :*: Nothing) -- ==> 3
t4 = foo (Nothing :*: Just True :*: Nothing) -- ==> 4
t5 = foo (Nothing :*: Just False :*: Nothing) -- ==> 4
t6 = foo (Just 1 :*: Just True :*: Just 'e') -- ==> 42
t7 = foo (Nothing :*: Nothing :*: Nothing) -- ==> error

t8 = boo (Just undefined :*: Just True :*: Nothing :*: Just 5) -- ==> 5
t9 = boo (Just undefined :*: Just True :*: Nothing :*: Nothing) -- ==> 0

第二次更新:请忽略我之前的“更新”:这是错误的。当然,您不能与 function nothing 匹配 - 这里只允许使用数据构造函数或变量,因此 nothing 被视为变量 (就像在您的示例中:someFun Nothing = Nothing 相当于 someFun a = a)。尽管作为“all Nothing”元组生成器,它仍然很有用,并且如果我们将“test”函数 isNothing 添加到我们的类中:

class Nothingable a where
nothing :: a
isNothing :: a -> Bool

instance Nothingable (Maybe a) where
nothing = Nothing
isNothing Nothing = True
isNothing _ = False

instance (Nothingable b) => Nothingable (Maybe a :*: b) where
nothing = Nothing :*: nothing
isNothing (Nothing :*: a) = isNothing a
isNothing _ = False

然后我们将能够使用 Haskel98 防护:

koo (Just 5 :*: Just "42" :*: Just True) = (Just True :*: Just 5.0 :*: Nothing)
koo ns | isNothing ns = nothing -- 'nothing' here generates a tuple of three members all set to Nothing

或奇特的 View 模式(带有“ViewPatterns”GHC 扩展):

koo (Just 5 :*: Just "42" :*: Just True) = (Just True :*: Just 5.0 :*: Nothing)
koo (Just 5 :*: (isNothing -> True)) = (Just True :*: Nothing :*: nothing)

和:

boo t = 
let (Just a :*: b) = t
in case b of
(Just _ :*: Nothing :*: Just c) -> c
(isNothing -> True) -> 0
_ -> error "failed"

对我之前的更新感到羞耻 - 它之所以有效,只是因为我在函数定义中将没有匹配作为最后一个案例(它匹配any 参数没有被前面的案例所接受 - 将其绑定(bind)到那个误导性的 nothing 变量)。抱歉,为此!

关于haskell - 如何拥有一种具有可索引但可选元素(要求 Haskell 中存在)的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4878423/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com