Haskell 类型类和类型签名

Haskell 类型类和类型签名,haskell,Haskell,我正在试验打字签名。这一个有效: nonz :: (Eq s, Num s, Show s) => ((->) a) s -> a -> Maybe s nonz f v = let w = f v in if w == 0 then Nothing else Just w main = do print $ nonz (+3) 7 print $ nonz (+4) (-4) 但当我将其设置为typeclass时,会出现一个错误: class Nonz

我正在试验打字签名。这一个有效:

nonz :: (Eq s, Num s, Show s) => ((->) a) s -> a -> Maybe s
nonz f v = let w = f v in if w == 0 then Nothing else Just w
main = do
    print $ nonz (+3) 7
    print $ nonz (+4) (-4)
但当我将其设置为typeclass时,会出现一个错误:

class Nonz z where
    nonz :: (Eq s, Num s, Show s) => z s -> a -> Maybe s
instance Nonz ((->) r) where
    nonz f v = let w = f v in if w == 0 then Nothing else Just w

main = do
    print $ nonz (+3) 7
    print $ nonz (+4) (-4)

类型
r
a
不匹配。如何将它们联系在一起?

如果您打算将
Nonz
应用于具有两个参数的类型构造函数,那么您应该相应地编写类。现在,您的类参数具有kind
*->*
。您可能希望它具有种类
*->*->*->*

你们班

class Nonz z where
    nonz :: (Eq s, Num s, Show s) => z s -> a -> Maybe s
建议的替代方案

class Nonz z where
    nonz :: (Eq s, Num s, Show s) => z a s -> a -> Maybe s
然后就可以编写您的实例了

instance Nonz (->) where
    nonz f v = let w = f v in if w == 0 then Nothing else Just w

如果您打算将
Nonz
应用于具有两个参数的类型构造函数,那么您应该相应地编写类。现在,您的类参数具有kind
*->*
。您可能希望它具有种类
*->*->*->*

你们班

class Nonz z where
    nonz :: (Eq s, Num s, Show s) => z s -> a -> Maybe s
建议的替代方案

class Nonz z where
    nonz :: (Eq s, Num s, Show s) => z a s -> a -> Maybe s
然后就可以编写您的实例了

instance Nonz (->) where
    nonz f v = let w = f v in if w == 0 then Nothing else Just w

实际上,我想了解函数如何成为函子实例。所以你的回答对我很有帮助。以下是完整的工作示例:

nonz' :: (Eq s, Num s) => (a -> s)   -> a -> Maybe s
{-
nonz' :: (Eq s, Num s) => ((->) a s) -> a -> Maybe s
nonz' :: (Eq s, Num s) => ((->) a) s -> a -> Maybe s
-}
nonz' f v = let w = f v in if w == 0 then Nothing else Just w

class Nonz z where
    nonz :: (Eq s, Num s) => z a s -> a -> Maybe s
instance Nonz (->) where
    nonz f v = let w = f v in if w == 0 then Nothing else Just w

main = do
    print $ nonz' (+3) 7
    print $ nonz' (+4) (-4)
    print $ nonz' length "foo"
    print $ nonz' length ""
    print $ nonz (+3) 7
    print $ nonz (+4) (-4)
    print $ nonz length "foo"
    print $ nonz length ""

非常感谢。

实际上,我想了解函数如何成为函子实例。所以你的回答对我很有帮助。以下是完整的工作示例:

nonz' :: (Eq s, Num s) => (a -> s)   -> a -> Maybe s
{-
nonz' :: (Eq s, Num s) => ((->) a s) -> a -> Maybe s
nonz' :: (Eq s, Num s) => ((->) a) s -> a -> Maybe s
-}
nonz' f v = let w = f v in if w == 0 then Nothing else Just w

class Nonz z where
    nonz :: (Eq s, Num s) => z a s -> a -> Maybe s
instance Nonz (->) where
    nonz f v = let w = f v in if w == 0 then Nothing else Just w

main = do
    print $ nonz' (+3) 7
    print $ nonz' (+4) (-4)
    print $ nonz' length "foo"
    print $ nonz' length ""
    print $ nonz (+3) 7
    print $ nonz (+4) (-4)
    print $ nonz length "foo"
    print $ nonz length ""

非常感谢。

您的代码几乎正确。您可以从
类中的签名中删除
a
参数,而只需使
nonz
返回
z(可能是s)
z
的内部可以隐藏
a
,作为其实现细节的一部分。此外,也不需要
Show s

以下是编译时的外观:

class Nonz z where
    nonz :: (Eq s, Num s) => z s -> z (Maybe s)

instance Nonz ((->) a) where
    nonz f v = let w = f v in if w == 0 then Nothing else Just w

main = do
    print $ nonz (+3) 7
    print $ nonz (+4) (-4)
这是因为
a
变量与
Nonz
类无关,因此它可以隐藏在实现中。当实现为
((->)a)
时,实例函数的签名将变为:

nonz :: (Eq s, Num s) => ((->) a) s -> ((->) a) (Maybe s)
通过使用中缀符号并删除括号,其与:

nonz :: (Eq s, Num s) => (a -> s) -> a -> Maybe s

您可能会进一步注意到,
nonz
的签名现在看起来很像对函子的操作。你是对的。实际上,您可以使用此实现为实现
Functor
的任何类型实现
Nonz

nonz' :: (Eq s, Num s) => s -> Maybe s
nonz' w = if w == 0 then Nothing else Just w

instance Nonz ((->) a) where
    nonz = fmap nonz'

现在您可能决定删除
Nonz
类,直接使用
fmap Nonz'

您的代码几乎是正确的。您可以从
类中的签名中删除
a
参数,而只需使
nonz
返回
z(可能是s)
z
的内部可以隐藏
a
,作为其实现细节的一部分。此外,也不需要
Show s

以下是编译时的外观:

class Nonz z where
    nonz :: (Eq s, Num s) => z s -> z (Maybe s)

instance Nonz ((->) a) where
    nonz f v = let w = f v in if w == 0 then Nothing else Just w

main = do
    print $ nonz (+3) 7
    print $ nonz (+4) (-4)
这是因为
a
变量与
Nonz
类无关,因此它可以隐藏在实现中。当实现为
((->)a)
时,实例函数的签名将变为:

nonz :: (Eq s, Num s) => ((->) a) s -> ((->) a) (Maybe s)
通过使用中缀符号并删除括号,其与:

nonz :: (Eq s, Num s) => (a -> s) -> a -> Maybe s

您可能会进一步注意到,
nonz
的签名现在看起来很像对函子的操作。你是对的。实际上,您可以使用此实现为实现
Functor
的任何类型实现
Nonz

nonz' :: (Eq s, Num s) => s -> Maybe s
nonz' w = if w == 0 then Nothing else Just w

instance Nonz ((->) a) where
    nonz = fmap nonz'

现在您可能决定删除
Nonz
类,直接使用
fmap Nonz'

作为旁注,
Nonz
实际上似乎根本没有使用
Show s
约束。您确定需要该约束吗?作为旁注,
nonz
实际上似乎根本没有使用
Show s
约束。你确定你需要那个约束吗?我很高兴你提到了
Functor
。我用这个想法写了你们班的另一个版本。请看我的答案。我很高兴你提到了
Functor
。我用这个想法写了你们班的另一个版本。请看我的答案。或
[w|w/=0]
,带单体理解。或
[w|w/=0]
,带单体理解。