gpt4 book ai didi

haskell - Haskell 中的类型系统

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

我无法理解为什么以下代码会导致错误。如果 Foo 的第二个字段改为类型Int ,代码运行没有错误。

Prelude> data Foo = Foo {foo_a :: Int, foo_b :: Float}
Prelude> let x = Foo 2 3.4
Prelude> unwords $ map (\fn -> (show . fn) x) [foo_a, foo_b]

<interactive>:4:46:
Couldn't match type `Float' with `Int'
Expected type: Foo -> Int
Actual type: Foo -> Float
In the expression: foo_b
In the second argument of `map', namely `[foo_a, foo_b]'
In the second argument of `($)', namely
`map (\ fn -> (show . fn) x) [foo_a, foo_b]'

为什么是 show无法接受不同类型的论点?当然,以下工作:
Prelude> show $ foo_a x
"2"
Prelude> show $ foo_b x
"3.4"

此外,鉴于这不起作用,推荐的应用方法是什么 show到数据类型的各个字段?

谢谢。

最佳答案

问题是 Haskell 中的列表是同质的(所有元素都具有相同的类型)。在 [foo_a, foo_b]您正在尝试创建具有两种不同类型的列表:Foo -> IntFoo -> Float .

一种解决方案是移动 show在列表中创建 Foo -> String 的列表:

Prelude> data Foo = Foo {foo_a :: Int, foo_b :: Float}
Prelude> let x = Foo 2 3.4
Prelude> unwords $ map (\fn -> fn x) [show . foo_a, show . foo_b]
"2 3.4"

( (\fn -> fn x) 可以写成 ($ x) )

另一种可能性是创建一个数据类型来统一您想要放入列表中的几种类型,模仿 heterogeneous collection .在你的情况下,它可能是这样的:
{-# LANGUAGE ExistentialQuantification #-}

data Showable b = forall a . Show a => MkShowable (b -> a)

pack :: Show a => (b -> a) -> Showable b
pack = MkShowable

unpack :: Showable b -> b -> String
unpack (MkShowable f) = show . f

然后,你可以这样做:
*Main> let x = Foo 2 3.4
*Main> unwords $ map (\fn -> unpack fn x) [pack foo_a, pack foo_b]
"2 3.4"

[更新]

我在玩 Data.Dynamic ,而且它似乎比我上面创建的存在类型更有希望。

让我们从:
{-# LANGUAGE DeriveDataTypeable #-}

import Control.Applicative
import Data.Dynamic
import Data.Maybe

data Foo = Foo {foo_a :: Int, foo_b :: Float}
deriving Typeable

get_a :: Dynamic -> Maybe (Foo -> Int)
get_a = fromDynamic

get_b :: Dynamic -> Maybe (Foo -> Float)
get_b = fromDynamic

getAsString :: Dynamic -> (Foo -> String)
getAsString dyn = fromJust $ (show .) <$> get_a dyn
<|> (show .) <$> get_b dyn
<|> error "Type mismatch"

在这种情况下,我们可以这样做:
*Main> let x = Foo 2 3.4
*Main> unwords $ map (\fn -> getAsString fn x) [toDyn foo_a, toDyn foo_b]
"2 3.4"

看起来我们必须编写更多代码才能达到相同的结果,但它实际上给了我们更多的灵 active 。而存在类型只专注于将字段显示为 String , 这里我们不限于此。如果现在我们想将所有字段都显示为 Int 怎么办? (在 Float 的情况下,我们要对值进行四舍五入)?
getAsInt :: Dynamic -> (Foo -> Int)
getAsInt dyn = fromJust $ get_a dyn
<|> (round .) <$> get_b dyn
<|> error "Type mismatch"

现在我们可以这样做:
*Main> let x = Foo 2 3.4
*Main> map (\fn -> getAsInt fn x) [toDyn foo_a, toDyn foo_b]
[2,3]

关于haskell - Haskell 中的类型系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32003234/

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