似乎newtype定义只是data遵循某些限制的定义(例如,只有一个构造函数),并且由于这些限制,运行时系统可以newtype更有效地处理s.并且未定义值的模式匹配处理略有不同.
但是假设Haskell只知道data定义,没有newtypes:编译器不能自己发现给定的数据定义是否遵守这些限制,并自动更有效地对待它?
我确定我错过了什么,必须有更深层次的理由.
我知道在Haskell中newtype经常被比较data,但我从更多的设计观点而不是技术问题中提出这种比较.
在不完全/ OO语言中,存在反模式" 原始的痴迷 ",其中原始类型的大量使用降低了程序的类型安全性并且引入了相同类型值的意外互换性,否则用于不同目的.例如,很多东西都可以是String,但如果编译器可以静态地知道我们的名字是什么以及我们想要成为地址中的城市,那将会很好.
那么,Haskell程序员用多长时间newtype来对其他原始值进行类型区分呢?使用type引入别名并为程序的可读性提供更清晰的语义,但不会阻止意外地交换值.当我学习haskell时,我注意到类型系统和我遇到的任何类型系统一样强大.因此,我认为这是一种自然而普遍的做法,但我没有看到太多或任何有关使用的讨论newtype.
当然,很多程序员都会以不同的方式做事,但这在haskell中是否常见?
我知道newtype在编译时擦除类型构造函数作为优化,因此newtype Foo = Foo Int结果只是一个Int. 换句话说,我不是在问这个问题。我的问题不是关于什么newtype。
相反,我试图理解为什么编译器在看到单值data构造函数时不能简单地应用这种优化本身。当我使用 时hlint,它足够聪明地告诉我单值data构造函数应该是newtype. (我从来没有犯过这个错误,但尝试过看看会发生什么。我的怀疑得到了证实。)
一个反对意见可能是,如果没有newtype,我们就不能使用GeneralizedNewTypeDeriving和其他这样的扩展。但这很容易解决。如果我们说……
data Foo m a b = Foo a (m b) deriving (Functor, Applicative, Monad)
Run Code Online (Sandbox Code Playgroud)
编译器可以直接告诉我们我们的愚蠢行为。
newtype当编译器总是可以自己解决时,为什么我们需要?
我很难理解为什么这两个片段在所谓的"穷人严格分析"下会产生不同的结果.
第一个示例使用data(假设一个正确的Applicative实例):
data Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
> getParser (pure (,) <*> literal ';' <*> undefined ) "abc"
*** Exception: Prelude.undefined
Run Code Online (Sandbox Code Playgroud)
第二个用途newtype.没有其他区别:
newtype Parser t a = Parser {
getParser :: [t] -> Maybe ([t], a)
}
> getParser (pure (,) <*> literal ';' <*> undefined ) "abc"
Nothing
Run Code Online (Sandbox Code Playgroud)
literal x是一个解析器,如果其参数与第一个标记匹配,则成功使用一个输入标记.所以在这个例子中,它失败了因为;不匹配a.但是,该data示例仍然看到下一个解析器未定义,而newtype示例则没有.
Haskell中的`data`和`newtype`之间的区别以及其他一些问题解决了数据和newtype之间的一般差异.我的问题非常具体.如果G是某种类型,是否有任何区别
data T = T !G
和
newtype T = T G?
它们似乎具有相同的严格属性,我不明白为什么编译器有任何理由以不同的方式编译它们,但也许我错过了一些东西.
我找到了解释Haskell 之间newtype和之间差异的答案data.但如果我有以下类型的同义词:
type Point = (Int,Int)
Run Code Online (Sandbox Code Playgroud)
这会更有效,而不是使用:
data Point = Pt (Int,Int) ?
Run Code Online (Sandbox Code Playgroud) 这是代码:
import Control.Applicative
-- newtype Parser a = Parser { runParser :: String -> [(a, String)] }
data Parser a = Parser { runParser :: String -> [(a, String)] }
instance Functor Parser where
fmap f (Parser p) = Parser (\s -> [(f x, s') | (x, s') <- p s ] )
instance Applicative Parser where
pure a = Parser (\s -> [(a, s)])
Parser q <*> Parser p = Parser (\s -> [(f x, s'') | (f, s') …Run Code Online (Sandbox Code Playgroud) 我正在练习Martin Odersky的Scala和Haskell的"Scala中的功能编程原理"课程.对于"设置为函数"练习,我定义了一个"toString"函数:
import Data.List (intercalate)
type Set = Int -> Bool
contains :: Set -> Int -> Bool
contains s elem = s elem
bound = 1000
toString :: Set -> String
toString s =
let xs = [(show x) | x <- [(-bound) .. bound], contains s x]
in "{" ++ (intercalate "," xs) ++ "}"
-- toString (\x -> x > -3 && x < 10)
-- => "{-2,-1,0,1,2,3,4,5,6,7,8,9}"
Run Code Online (Sandbox Code Playgroud)
能够定义:很高兴:
instance Show Set where
show Set = ... …Run Code Online (Sandbox Code Playgroud) 我定义了:
type Network = [(Matrix Double,Vector Double)]
Run Code Online (Sandbox Code Playgroud)
Matrix和Vector来自hmatrix库.从hmatrix的文档中可以看出,Matrix Double和Vector Double已经是Num的实例.由于我需要添加和减少网络安静,我还希望网络成为Num的一个实例.我试过了
instance Num Network where
(+) = zipWith (\(m,v) (n,w) -> (m+n,v+w))
(-) = zipWith (\(m,v) (n,w) -> (m-n,v-w))
(*) = zipWith (\(m,v) (n,w) -> (m*n,v*w))
Run Code Online (Sandbox Code Playgroud)
但我收到错误:非法实例声明.